From 325377b57338e700317f5e423e5b0f1c08d99a39 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Fri, 16 Jun 2017 21:03:44 +0000 Subject: [PATCH] Vendor import of clang trunk r305575: https://llvm.org/svn/llvm-project/cfe/trunk@305575 --- docs/ClangFormatStyleOptions.rst | 10 +- docs/ReleaseNotes.rst | 25 ++ docs/UndefinedBehaviorSanitizer.rst | 6 + include/clang/Basic/AllDiagnostics.h | 2 +- include/clang/Basic/BuiltinsPPC.def | 8 +- .../Basic/DiagnosticSerializationKinds.td | 34 +- include/clang/Format/Format.h | 36 ++ include/clang/Frontend/FrontendOptions.h | 4 +- include/clang/Lex/MacroArgs.h | 16 +- include/clang/Sema/Sema.h | 2 + lib/AST/ASTContext.cpp | 3 +- lib/AST/ExprClassification.cpp | 4 +- lib/AST/ExprConstant.cpp | 33 +- lib/AST/ItaniumMangle.cpp | 2 + lib/AST/ODRHash.cpp | 47 ++- lib/CodeGen/BackendUtil.cpp | 8 +- lib/CodeGen/CGBuiltin.cpp | 21 + lib/CodeGen/CGCall.cpp | 2 + lib/CodeGen/CGCoroutine.cpp | 66 ++- lib/CodeGen/CGDebugInfo.cpp | 18 +- lib/CodeGen/CGExpr.cpp | 47 ++- lib/CodeGen/CGExprScalar.cpp | 51 ++- lib/CodeGen/CGOpenMPRuntime.cpp | 2 +- lib/CodeGen/CodeGenFunction.h | 4 + lib/CodeGen/CodeGenModule.cpp | 10 +- lib/CodeGen/CodeGenModule.h | 7 +- lib/Driver/ToolChains/Clang.cpp | 3 + lib/Format/Format.cpp | 16 +- lib/Format/NamespaceEndCommentsFixer.cpp | 64 ++- lib/Format/UnwrappedLineFormatter.cpp | 80 +++- lib/Format/UnwrappedLineParser.cpp | 5 + lib/Format/WhitespaceManager.h | 4 + lib/Frontend/ASTConsumers.cpp | 2 +- lib/Frontend/CompilerInvocation.cpp | 10 +- lib/Index/IndexDecl.cpp | 13 + lib/Index/IndexSymbol.cpp | 4 + lib/Lex/MacroArgs.cpp | 20 +- lib/Sema/SemaCodeComplete.cpp | 10 +- lib/Sema/SemaCoroutine.cpp | 35 +- lib/Sema/SemaDeclAttr.cpp | 14 +- lib/Sema/SemaExpr.cpp | 8 +- lib/Sema/SemaExprCXX.cpp | 9 +- lib/Sema/SemaLambda.cpp | 16 +- lib/Sema/SemaStmt.cpp | 58 ++- lib/Serialization/ASTReader.cpp | 154 +++++++ lib/Serialization/ASTReaderDecl.cpp | 85 ++-- lib/StaticAnalyzer/Core/CallEvent.cpp | 6 + test/Analysis/DynamicTypePropagation.m | 12 + test/Analysis/analyzer_test.py | 31 +- test/CodeCompletion/member-access.cpp | 18 + test/CodeGen/Inputs/thinlto-multi-module.ll | 9 + test/CodeGen/attributes.c | 10 + test/CodeGen/avx-builtins.c | 48 +++ test/CodeGen/builtins-ppc-error.c | 33 ++ test/CodeGen/dependent-lib.c | 8 +- test/CodeGen/linker-option.c | 4 +- test/CodeGen/mips-debug-info-bitfield.c | 17 + test/CodeGen/pragma-comment.c | 4 +- test/CodeGen/pragma-detect_mismatch.c | 4 +- test/CodeGen/thinlto-backend-option.ll | 6 +- test/CodeGen/thinlto-multi-module.ll | 4 +- test/CodeGen/ubsan-pointer-overflow.m | 72 +++- test/CodeGen/ubsan-volatile.c | 7 + test/CodeGenCXX/ms-thread_local.cpp | 4 +- test/CodeGenCoroutines/coro-await.cpp | 50 ++- test/CodeGenObjC/availability-cf-link-guard.m | 5 +- test/Coverage/ast-printing.c | 1 + test/Coverage/ast-printing.cpp | 1 + test/Driver/m_and_mm.c | 12 + test/Index/Core/index-source.cpp | 44 +- test/Index/availability.c | 18 +- test/Misc/pr32207.c | 4 + test/Modules/autolink.m | 6 +- test/Modules/autolinkTBD.m | 6 +- test/Modules/module-impl-with-link.c | 3 +- test/Modules/odr_hash.cpp | 391 +++++++++++++++++- test/Sema/integer-overflow.c | 8 - test/Sema/xray-log-args-class.cpp | 7 + test/SemaCXX/co_await-range-for.cpp | 165 ++++++++ test/SemaCXX/cxx1z-decomposition.cpp | 6 + test/SemaCXX/nested-name-spec.cpp | 7 + test/SemaCXX/warn-unused-lambda-capture.cpp | 5 + tools/clang-format/git-clang-format | 2 + tools/libclang/CIndex.cpp | 120 ++++-- unittests/AST/CommentLexer.cpp | 3 +- unittests/ASTMatchers/ASTMatchersTest.h | 9 +- unittests/Basic/VirtualFileSystemTest.cpp | 6 +- unittests/Format/FormatTest.cpp | 261 ++++++++++++ .../Format/NamespaceEndCommentsFixerTest.cpp | 56 +++ unittests/Lex/LexerTest.cpp | 73 +++- unittests/Tooling/LookupTest.cpp | 6 +- 91 files changed, 2244 insertions(+), 406 deletions(-) create mode 100644 test/CodeGen/Inputs/thinlto-multi-module.ll create mode 100644 test/CodeGen/mips-debug-info-bitfield.c create mode 100644 test/CodeGen/ubsan-volatile.c create mode 100644 test/Misc/pr32207.c create mode 100644 test/Sema/xray-log-args-class.cpp create mode 100644 test/SemaCXX/co_await-range-for.cpp diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst index 9e0bacaf7c14..fb014241809c 100644 --- a/docs/ClangFormatStyleOptions.rst +++ b/docs/ClangFormatStyleOptions.rst @@ -521,12 +521,12 @@ the configuration (without a prefix: ``Auto``). .. code-block:: c++ true: - class foo {}; - - false: class foo {}; + false: + class foo {}; + * ``bool AfterControlStatement`` Wrap control statements (``if``/``for``/``while``/``switch``/..). .. code-block:: c++ @@ -603,12 +603,12 @@ the configuration (without a prefix: ``Auto``). struct foo { int x; - } + }; false: struct foo { int x; - } + }; * ``bool AfterUnion`` Wrap union definitions. diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index f7e31e5c98d5..f9a3317811eb 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -187,6 +187,31 @@ Static Analyzer ... +Undefined Behavior Sanitizer (UBSan) +------------------------------------ + +- The Undefined Behavior Sanitizer has a new check for pointer overflow. This + check is on by default. The flag to control this functionality is + -fsanitize=pointer-overflow. + + Pointer overflow is an indicator of undefined behavior: when a pointer + indexing expression wraps around the address space, or produces other + unexpected results, its result may not point to a valid object. + +- UBSan has several new checks which detect violations of nullability + annotations. These checks are off by default. The flag to control this group + of checks is -fsanitize=nullability. The checks can be individially enabled + by -fsanitize=nullability-arg (which checks calls), + -fsanitize=nullability-assign (which checks assignments), and + -fsanitize=nullability-return (which checks return statements). + +- UBSan can now detect invalid loads from bitfields and from ObjC BOOLs. + +- UBSan can now avoid emitting unnecessary type checks in C++ class methods and + in several other cases where the result is known at compile-time. UBSan can + also avoid emitting unnecessary overflow checks in arithmetic expressions + with promoted integer operands. + Core Analysis Improvements ========================== diff --git a/docs/UndefinedBehaviorSanitizer.rst b/docs/UndefinedBehaviorSanitizer.rst index ea776a770470..85dd549baaf8 100644 --- a/docs/UndefinedBehaviorSanitizer.rst +++ b/docs/UndefinedBehaviorSanitizer.rst @@ -148,6 +148,12 @@ You can also use the following check groups: nullability does not have undefined behavior, it is often unintentional, so UBSan offers to catch it. +Volatile +-------- + +The ``null``, ``alignment``, ``object-size``, and ``vptr`` checks do not apply +to pointers to types with the ``volatile`` qualifier. + Stack traces and report symbolization ===================================== If you want UBSan to print symbolized stack trace for each error report, you diff --git a/include/clang/Basic/AllDiagnostics.h b/include/clang/Basic/AllDiagnostics.h index 18a2b8a31871..fc861a1952a5 100644 --- a/include/clang/Basic/AllDiagnostics.h +++ b/include/clang/Basic/AllDiagnostics.h @@ -28,7 +28,7 @@ namespace clang { template class StringSizerHelper { - char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1]; + static_assert(SizeOfStr <= FieldType(~0U), "Field too small!"); public: enum { Size = SizeOfStr }; }; diff --git a/include/clang/Basic/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def index 119490314b26..faa70a48edc3 100644 --- a/include/clang/Basic/BuiltinsPPC.def +++ b/include/clang/Basic/BuiltinsPPC.def @@ -51,10 +51,10 @@ BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "") BUILTIN(__builtin_altivec_vrfip, "V4fV4f", "") -BUILTIN(__builtin_altivec_vcfsx, "V4fV4ii", "") -BUILTIN(__builtin_altivec_vcfux, "V4fV4ii", "") -BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fi", "") -BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fi", "") +BUILTIN(__builtin_altivec_vcfsx, "V4fV4iIi", "") +BUILTIN(__builtin_altivec_vcfux, "V4fV4iIi", "") +BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fIi", "") +BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fIi", "") BUILTIN(__builtin_altivec_dss, "vUi", "") BUILTIN(__builtin_altivec_dssall, "v", "") diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td index 7c9e8c8980aa..0a59a633232c 100644 --- a/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/include/clang/Basic/DiagnosticSerializationKinds.td @@ -121,10 +121,12 @@ def err_module_odr_violation_mismatch_decl : Error< "%q0 has different definitions in different modules; first difference is " "%select{definition in module '%2'|defined here}1 found " "%select{end of class|public access specifier|private access specifier|" - "protected access specifier|static assert|field|method}3">; + "protected access specifier|static assert|field|method|type alias|typedef|" + "data member}3">; def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found " "%select{end of class|public access specifier|private access specifier|" - "protected access specifier|static assert|field|method}1">; + "protected access specifier|static assert|field|method|type alias|typedef|" + "data member}1">; def err_module_odr_violation_mismatch_decl_diff : Error< "%q0 has different definitions in different modules; first difference is " @@ -149,7 +151,17 @@ def err_module_odr_violation_mismatch_decl_diff : Error< "method %4 is %select{not inline|inline}5|" "method %4 that has %5 parameter%s5|" "method %4 with %ordinal5 parameter of type %6%select{| decayed from %8}7|" - "method %4 with %ordinal5 parameter named %6}3">; + "method %4 with %ordinal5 parameter named %6|" + "method %4 with %ordinal5 parameter with%select{out|}6 a default argument|" + "method %4 with %ordinal5 parameter with a default argument|" + "%select{typedef|type alias}4 name %5|" + "%select{typedef|type alias}4 %5 with underlying type %6|" + "data member with name %4|" + "data member %4 with type %5|" + "data member %4 with%select{out|}5 an initializer|" + "data member %4 with an initializer|" + "data member %4 %select{is constexpr|is not constexpr}5|" + "}3">; def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " "%select{" @@ -172,15 +184,27 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " "method %2 is %select{not inline|inline}3|" "method %2 that has %3 parameter%s3|" "method %2 with %ordinal3 parameter of type %4%select{| decayed from %6}5|" - "method %2 with %ordinal3 parameter named %4}1">; + "method %2 with %ordinal3 parameter named %4|" + "method %2 with %ordinal3 parameter with%select{out|}4 a default argument|" + "method %2 with %ordinal3 parameter with a different default argument|" + "%select{typedef|type alias}2 name %3|" + "%select{typedef|type alias}2 %3 with different underlying type %4|" + "data member with name %2|" + "data member %2 with different type %3|" + "data member %2 with%select{out|}3 an initializer|" + "data member %2 with a different initializer|" + "data member %2 %select{is constexpr|is not constexpr}3|" + "}1">; def err_module_odr_violation_mismatch_decl_unknown : Error< "%q0 %select{with definition in module '%2'|defined here}1 has different " "definitions in different modules; first difference is this " - "%select{||||static assert|field|method|unexpected decl}3">; + "%select{||||static assert|field|method|type alias|typedef|data member|" + "unexpected decl}3">; def note_module_odr_violation_mismatch_decl_unknown : Note< "but in '%0' found " "%select{||||different static assert|different field|different method|" + "different type alias|different typedef|different data member|" "another unexpected decl}1">; def warn_duplicate_module_file_extension : Warning< diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index 7ec3e22ca4d7..1891c06eba51 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -688,6 +688,18 @@ struct FormatStyle { bool BeforeElse; /// \brief Indent the wrapped braces themselves. bool IndentBraces; + /// \brief If ``false``, empty function body can be put on a single line. + /// This option is used only if the opening brace of the function has + /// already been wrapped, i.e. the `AfterFunction` brace wrapping mode is + /// set, and the function could/should not be put on a single line (as per + /// `AllowShortFunctionsOnASingleLine` and constructor formatting options). + /// \code + /// int f() vs. inf f() + /// {} { + /// } + /// \endcode + /// + bool SplitEmptyFunctionBody; }; /// \brief Control of individual brace wrapping cases. @@ -779,6 +791,29 @@ struct FormatStyle { /// \endcode bool BreakBeforeInheritanceComma; + /// \brief If ``true``, consecutive namespace declarations will be on the same + /// line. If ``false``, each namespace is declared on a new line. + /// \code + /// true: + /// namespace Foo { namespace Bar { + /// }} + /// + /// false: + /// namespace Foo { + /// namespace Bar { + /// } + /// } + /// \endcode + /// + /// If it does not fit on a single line, the overflowing namespaces get + /// wrapped: + /// \code + /// namespace Foo { namespace Bar { + /// namespace Extra { + /// }}} + /// \endcode + bool CompactNamespaces; + /// \brief If the constructor initializers don't fit on a line, put each /// initializer on its own line. /// \code @@ -1410,6 +1445,7 @@ struct FormatStyle { BreakBeforeBraces == R.BreakBeforeBraces && BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators && BreakConstructorInitializers == R.BreakConstructorInitializers && + CompactNamespaces == R.CompactNamespaces && BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations && BreakStringLiterals == R.BreakStringLiterals && ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas && diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 36c046891b47..e757a7e397e3 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -317,8 +317,8 @@ public: /// \brief Auxiliary triple for CUDA compilation. std::string AuxTriple; - /// \brief If non-empty, search the pch input file as it was a header - // included by this file. + /// \brief If non-empty, search the pch input file as if it was a header + /// included by this file. std::string FindPchSource; /// Filename to write statistics to. diff --git a/include/clang/Lex/MacroArgs.h b/include/clang/Lex/MacroArgs.h index 7b2a48561ff6..cfe46ceb0979 100644 --- a/include/clang/Lex/MacroArgs.h +++ b/include/clang/Lex/MacroArgs.h @@ -53,9 +53,12 @@ class MacroArgs { /// Preprocessor owns which we use to avoid thrashing malloc/free. MacroArgs *ArgCache; - MacroArgs(unsigned NumToks, bool varargsElided) - : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), - ArgCache(nullptr) {} + /// MacroArgs - The number of arguments the invoked macro expects. + unsigned NumMacroArgs; + + MacroArgs(unsigned NumToks, bool varargsElided, unsigned MacroArgs) + : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), + ArgCache(nullptr), NumMacroArgs(MacroArgs) {} ~MacroArgs() = default; public: @@ -94,10 +97,9 @@ public: SourceLocation ExpansionLocStart, SourceLocation ExpansionLocEnd); - /// getNumArguments - Return the number of arguments passed into this macro - /// invocation. - unsigned getNumArguments() const { return NumUnexpArgTokens; } - + /// getNumMacroArguments - Return the number of arguments the invoked macro + /// expects. + unsigned getNumMacroArguments() const { return NumMacroArgs; } /// isVarargsElidedUse - Return true if this is a C99 style varargs macro /// invocation and there was no argument specified for the "..." argument. If diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 8025668e664e..1dedf4ba24ce 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -8364,6 +8364,8 @@ public: //===--------------------------------------------------------------------===// // C++ Coroutines TS // + bool ActOnCoroutineBodyStart(Scope *S, SourceLocation KwLoc, + StringRef Keyword); ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E); ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E); StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 62b19685c677..2300801c1a9c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3565,7 +3565,7 @@ QualType ASTContext::getSubstTemplateTypeParmPackType( = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon, ArgPack); Types.push_back(SubstParm); - SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); + SubstTemplateTypeParmPackTypes.InsertNode(SubstParm, InsertPos); return QualType(SubstParm, 0); } @@ -8547,6 +8547,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, HowLong = 2; break; } + break; } } diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index c035a42439a3..d149bdd0cdf9 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -190,7 +190,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::ArrayInitIndexExprClass: case Expr::NoInitExprClass: case Expr::DesignatedInitUpdateExprClass: - case Expr::CoyieldExprClass: return Cl::CL_PRValue; // Next come the complicated cases. @@ -414,7 +413,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { return ClassifyInternal(Ctx, cast(E)->getInit(0)); case Expr::CoawaitExprClass: - return ClassifyInternal(Ctx, cast(E)->getResumeExpr()); + case Expr::CoyieldExprClass: + return ClassifyInternal(Ctx, cast(E)->getResumeExpr()); } llvm_unreachable("unhandled expression kind in classification"); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 17d0ce67dcf9..768947d00ac4 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -4588,7 +4588,7 @@ public: } bool handleCallExpr(const CallExpr *E, APValue &Result, - const LValue *ResultSlot) { + const LValue *ResultSlot) { const Expr *Callee = E->getCallee()->IgnoreParens(); QualType CalleeType = Callee->getType(); @@ -4597,23 +4597,6 @@ public: auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs()); bool HasQualifier = false; - struct EvaluateIgnoredRAII { - public: - EvaluateIgnoredRAII(EvalInfo &Info, llvm::ArrayRef ToEval) - : Info(Info), ToEval(ToEval) {} - ~EvaluateIgnoredRAII() { - if (Info.noteFailure()) { - for (auto E : ToEval) - EvaluateIgnoredValue(Info, E); - } - } - void cancel() { ToEval = {}; } - void drop_front() { ToEval = ToEval.drop_front(); } - private: - EvalInfo &Info; - llvm::ArrayRef ToEval; - } EvalArguments(Info, Args); - // Extract function decl and 'this' pointer from the callee. if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) { const ValueDecl *Member = nullptr; @@ -4663,12 +4646,10 @@ public: if (Args.empty()) return Error(E); - const Expr *FirstArg = Args[0]; - Args = Args.drop_front(); - EvalArguments.drop_front(); - if (!EvaluateObjectArgument(Info, FirstArg, ThisVal)) + if (!EvaluateObjectArgument(Info, Args[0], ThisVal)) return false; This = &ThisVal; + Args = Args.slice(1); } else if (MD && MD->isLambdaStaticInvoker()) { // Map the static invoker for the lambda back to the call operator. // Conveniently, we don't have to slice out the 'this' argument (as is @@ -4720,12 +4701,8 @@ public: const FunctionDecl *Definition = nullptr; Stmt *Body = FD->getBody(Definition); - if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body)) - return false; - - EvalArguments.cancel(); - - if (!HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info, + if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) || + !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info, Result, ResultSlot)) return false; diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index c9bb45a37eb5..dc25e5213bae 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -4550,9 +4550,11 @@ CXXNameMangler::makeFunctionReturnTypeTags(const FunctionDecl *FD) { const FunctionProtoType *Proto = cast(FD->getType()->getAs()); + FunctionTypeDepthState saved = TrackReturnTypeTags.FunctionTypeDepth.push(); TrackReturnTypeTags.FunctionTypeDepth.enterResultType(); TrackReturnTypeTags.mangleType(Proto->getReturnType()); TrackReturnTypeTags.FunctionTypeDepth.leaveResultType(); + TrackReturnTypeTags.FunctionTypeDepth.pop(saved); return TrackReturnTypeTags.AbiTagsRoot.getSortedUniqueUsedAbiTags(); } diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp index 08593da89bbd..05bed658f3fc 100644 --- a/lib/AST/ODRHash.cpp +++ b/lib/AST/ODRHash.cpp @@ -140,7 +140,33 @@ void ODRHash::AddTemplateName(TemplateName Name) { } } -void ODRHash::AddTemplateArgument(TemplateArgument TA) {} +void ODRHash::AddTemplateArgument(TemplateArgument TA) { + const auto Kind = TA.getKind(); + ID.AddInteger(Kind); + + switch (Kind) { + case TemplateArgument::Null: + case TemplateArgument::Type: + case TemplateArgument::Declaration: + case TemplateArgument::NullPtr: + case TemplateArgument::Integral: + break; + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + AddTemplateName(TA.getAsTemplateOrTemplatePattern()); + break; + case TemplateArgument::Expression: + AddStmt(TA.getAsExpr()); + break; + case TemplateArgument::Pack: + ID.AddInteger(TA.pack_size()); + for (auto SubTA : TA.pack_elements()) { + AddTemplateArgument(SubTA); + } + break; + } +} + void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {} void ODRHash::clear() { @@ -226,6 +252,17 @@ public: Inherited::VisitValueDecl(D); } + void VisitVarDecl(const VarDecl *D) { + Hash.AddBoolean(D->isStaticLocal()); + Hash.AddBoolean(D->isConstexpr()); + const bool HasInit = D->hasInit(); + Hash.AddBoolean(HasInit); + if (HasInit) { + AddStmt(D->getInit()); + } + Inherited::VisitVarDecl(D); + } + void VisitParmVarDecl(const ParmVarDecl *D) { // TODO: Handle default arguments. Inherited::VisitParmVarDecl(D); @@ -310,6 +347,7 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) { case Decl::StaticAssert: case Decl::TypeAlias: case Decl::Typedef: + case Decl::Var: return true; } } @@ -527,6 +565,13 @@ public: Hash.AddTemplateName(T->getTemplateName()); VisitType(T); } + + void VisitTemplateTypeParmType(const TemplateTypeParmType *T) { + ID.AddInteger(T->getDepth()); + ID.AddInteger(T->getIndex()); + Hash.AddBoolean(T->isParameterPack()); + AddDecl(T->getDecl()); + } }; void ODRHash::AddType(const Type *T) { diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 9c4316fb1cd5..bd01902a032b 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -964,11 +964,11 @@ Expected clang::FindThinLTOModule(MemoryBufferRef MBRef) { if (!BMsOrErr) return BMsOrErr.takeError(); - // The bitcode file may contain multiple modules, we want the one with a - // summary. + // The bitcode file may contain multiple modules, we want the one that is + // marked as being the ThinLTO module. for (BitcodeModule &BM : *BMsOrErr) { - Expected HasSummary = BM.hasSummary(); - if (HasSummary && *HasSummary) + Expected LTOInfo = BM.getLTOInfo(); + if (LTOInfo && LTOInfo->IsThinLTO) return BM; } diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 3b4f8854a9ca..8f0c22d1f7ef 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -7923,6 +7923,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, } // We can't handle 8-31 immediates with native IR, use the intrinsic. + // Except for predicates that create constants. Intrinsic::ID ID; switch (BuiltinID) { default: llvm_unreachable("Unsupported intrinsic!"); @@ -7930,12 +7931,32 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, ID = Intrinsic::x86_sse_cmp_ps; break; case X86::BI__builtin_ia32_cmpps256: + // _CMP_TRUE_UQ, _CMP_TRUE_US produce -1,-1... vector + // on any input and _CMP_FALSE_OQ, _CMP_FALSE_OS produce 0, 0... + if (CC == 0xf || CC == 0xb || CC == 0x1b || CC == 0x1f) { + Value *Constant = (CC == 0xf || CC == 0x1f) ? + llvm::Constant::getAllOnesValue(Builder.getInt32Ty()) : + llvm::Constant::getNullValue(Builder.getInt32Ty()); + Value *Vec = Builder.CreateVectorSplat( + Ops[0]->getType()->getVectorNumElements(), Constant); + return Builder.CreateBitCast(Vec, Ops[0]->getType()); + } ID = Intrinsic::x86_avx_cmp_ps_256; break; case X86::BI__builtin_ia32_cmppd: ID = Intrinsic::x86_sse2_cmp_pd; break; case X86::BI__builtin_ia32_cmppd256: + // _CMP_TRUE_UQ, _CMP_TRUE_US produce -1,-1... vector + // on any input and _CMP_FALSE_OQ, _CMP_FALSE_OS produce 0, 0... + if (CC == 0xf || CC == 0xb || CC == 0x1b || CC == 0x1f) { + Value *Constant = (CC == 0xf || CC == 0x1f) ? + llvm::Constant::getAllOnesValue(Builder.getInt64Ty()) : + llvm::Constant::getNullValue(Builder.getInt64Ty()); + Value *Vec = Builder.CreateVectorSplat( + Ops[0]->getType()->getVectorNumElements(), Constant); + return Builder.CreateBitCast(Vec, Ops[0]->getType()); + } ID = Intrinsic::x86_avx_cmp_pd_256; break; } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 079064733585..c65dc18be306 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -1795,6 +1795,8 @@ void CodeGenModule::ConstructAttributeList( FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); if (TargetDecl->hasAttr()) FuncAttrs.addAttribute(llvm::Attribute::NoReturn); + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute(llvm::Attribute::Cold); if (TargetDecl->hasAttr()) FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate); if (TargetDecl->hasAttr()) diff --git a/lib/CodeGen/CGCoroutine.cpp b/lib/CodeGen/CGCoroutine.cpp index bc5f6327c9a0..a65faa602b33 100644 --- a/lib/CodeGen/CGCoroutine.cpp +++ b/lib/CodeGen/CGCoroutine.cpp @@ -148,25 +148,18 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData &Coro, AwaitKind Kind) { // // See llvm's docs/Coroutines.rst for more details. // -static RValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro, +namespace { + struct LValueOrRValue { + LValue LV; + RValue RV; + }; +} +static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro, CoroutineSuspendExpr const &S, AwaitKind Kind, AggValueSlot aggSlot, - bool ignoreResult) { + bool ignoreResult, bool forLValue) { auto *E = S.getCommonExpr(); - // FIXME: rsmith 5/22/2017. Does it still make sense for us to have a - // UO_Coawait at all? As I recall, the only purpose it ever had was to - // represent a dependent co_await expression that couldn't yet be resolved to - // a CoawaitExpr. But now we have (and need!) a separate DependentCoawaitExpr - // node to store unqualified lookup results, it seems that the UnaryOperator - // portion of the representation serves no purpose (and as seen in this patch, - // it's getting in the way). Can we remove it? - - // Skip passthrough operator co_await (present when awaiting on an LValue). - if (auto *UO = dyn_cast(E)) - if (UO->getOpcode() == UO_Coawait) - E = UO->getSubExpr(); - auto Binder = CodeGenFunction::OpaqueValueMappingData::bind(CGF, S.getOpaqueValue(), E); auto UnbindOnExit = llvm::make_scope_exit([&] { Binder.unbind(CGF); }); @@ -217,7 +210,12 @@ static RValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro, // Emit await_resume expression. CGF.EmitBlock(ReadyBlock); - return CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult); + LValueOrRValue Res; + if (forLValue) + Res.LV = CGF.EmitLValue(S.getResumeExpr()); + else + Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult); + return Res; } RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E, @@ -225,13 +223,13 @@ RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E, bool ignoreResult) { return emitSuspendExpression(*this, *CurCoro.Data, E, CurCoro.Data->CurrentAwaitKind, aggSlot, - ignoreResult); + ignoreResult, /*forLValue*/false).RV; } RValue CodeGenFunction::EmitCoyieldExpr(const CoyieldExpr &E, AggValueSlot aggSlot, bool ignoreResult) { return emitSuspendExpression(*this, *CurCoro.Data, E, AwaitKind::Yield, - aggSlot, ignoreResult); + aggSlot, ignoreResult, /*forLValue*/false).RV; } void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) { @@ -240,6 +238,38 @@ void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) { EmitBranchThroughCleanup(CurCoro.Data->FinalJD); } + +#ifndef NDEBUG +static QualType getCoroutineSuspendExprReturnType(const ASTContext &Ctx, + const CoroutineSuspendExpr *E) { + const auto *RE = E->getResumeExpr(); + // Is it possible for RE to be a CXXBindTemporaryExpr wrapping + // a MemberCallExpr? + assert(isa(RE) && "unexpected suspend expression type"); + return cast(RE)->getCallReturnType(Ctx); +} +#endif + +LValue +CodeGenFunction::EmitCoawaitLValue(const CoawaitExpr *E) { + assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && + "Can't have a scalar return unless the return type is a " + "reference type!"); + return emitSuspendExpression(*this, *CurCoro.Data, *E, + CurCoro.Data->CurrentAwaitKind, AggValueSlot::ignored(), + /*ignoreResult*/false, /*forLValue*/true).LV; +} + +LValue +CodeGenFunction::EmitCoyieldLValue(const CoyieldExpr *E) { + assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() && + "Can't have a scalar return unless the return type is a " + "reference type!"); + return emitSuspendExpression(*this, *CurCoro.Data, *E, + AwaitKind::Yield, AggValueSlot::ignored(), + /*ignoreResult*/false, /*forLValue*/true).LV; +} + // Hunts for the parameter reference in the parameter copy/move declaration. namespace { struct GetParamRef : public StmtVisitor { diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index ebb264eb61c9..b00d296fe34a 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1041,7 +1041,13 @@ llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl, assert(SizeInBits > 0 && "found named 0-width bitfield"); uint64_t StorageOffsetInBits = CGM.getContext().toBits(BitFieldInfo.StorageOffset); - uint64_t OffsetInBits = StorageOffsetInBits + BitFieldInfo.Offset; + uint64_t Offset = BitFieldInfo.Offset; + // The bit offsets for big endian machines are reversed for big + // endian target, compensate for that as the DIDerivedType requires + // un-reversed offsets. + if (CGM.getDataLayout().isBigEndian()) + Offset = BitFieldInfo.StorageSize - BitFieldInfo.Size - Offset; + uint64_t OffsetInBits = StorageOffsetInBits + Offset; llvm::DINode::DIFlags Flags = getAccessFlag(BitFieldDecl->getAccess(), RD); return DBuilder.createBitFieldMemberType( RecordTy, Name, File, Line, SizeInBits, OffsetInBits, StorageOffsetInBits, @@ -3484,13 +3490,13 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage, if (VD->hasAttr()) { // Here, we need an offset *into* the alloca. CharUnits offset = CharUnits::fromQuantity(32); - Expr.push_back(llvm::dwarf::DW_OP_plus); + Expr.push_back(llvm::dwarf::DW_OP_plus_uconst); // offset of __forwarding field offset = CGM.getContext().toCharUnitsFromBits( CGM.getTarget().getPointerWidth(0)); Expr.push_back(offset.getQuantity()); Expr.push_back(llvm::dwarf::DW_OP_deref); - Expr.push_back(llvm::dwarf::DW_OP_plus); + Expr.push_back(llvm::dwarf::DW_OP_plus_uconst); // offset of x field offset = CGM.getContext().toCharUnitsFromBits(XOffset); Expr.push_back(offset.getQuantity()); @@ -3599,17 +3605,17 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( SmallVector addr; addr.push_back(llvm::dwarf::DW_OP_deref); - addr.push_back(llvm::dwarf::DW_OP_plus); + addr.push_back(llvm::dwarf::DW_OP_plus_uconst); addr.push_back(offset.getQuantity()); if (isByRef) { addr.push_back(llvm::dwarf::DW_OP_deref); - addr.push_back(llvm::dwarf::DW_OP_plus); + addr.push_back(llvm::dwarf::DW_OP_plus_uconst); // offset of __forwarding field 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); + addr.push_back(llvm::dwarf::DW_OP_plus_uconst); // offset of x field offset = CGM.getContext().toCharUnitsFromBits(XOffset); addr.push_back(offset.getQuantity()); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 9f800a75b5bc..7359006677f4 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -549,6 +549,11 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, if (Ptr->getType()->getPointerAddressSpace()) return; + // Don't check pointers to volatile data. The behavior here is implementation- + // defined. + if (Ty.isVolatileQualified()) + return; + SanitizerScope SanScope(this); SmallVector, 3> Checks; @@ -1158,6 +1163,11 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::MaterializeTemporaryExprClass: return EmitMaterializeTemporaryExpr(cast(E)); + + case Expr::CoawaitExprClass: + return EmitCoawaitLValue(cast(E)); + case Expr::CoyieldExprClass: + return EmitCoyieldLValue(cast(E)); } } @@ -3002,10 +3012,11 @@ static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF, llvm::Value *ptr, ArrayRef indices, bool inbounds, + bool signedIndices, SourceLocation loc, const llvm::Twine &name = "arrayidx") { if (inbounds) { - return CGF.EmitCheckedInBoundsGEP(ptr, indices, loc, name); + return CGF.EmitCheckedInBoundsGEP(ptr, indices, signedIndices, loc, name); } else { return CGF.Builder.CreateGEP(ptr, indices, name); } @@ -3038,7 +3049,7 @@ static QualType getFixedSizeElementType(const ASTContext &ctx, static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, ArrayRef indices, QualType eltType, bool inbounds, - SourceLocation loc, + bool signedIndices, SourceLocation loc, const llvm::Twine &name = "arrayidx") { // All the indices except that last must be zero. #ifndef NDEBUG @@ -3058,8 +3069,8 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, CharUnits eltAlign = getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize); - llvm::Value *eltPtr = - emitArraySubscriptGEP(CGF, addr.getPointer(), indices, inbounds, loc, name); + llvm::Value *eltPtr = emitArraySubscriptGEP( + CGF, addr.getPointer(), indices, inbounds, signedIndices, loc, name); return Address(eltPtr, eltAlign); } @@ -3069,6 +3080,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, // in lexical order (this complexity is, sadly, required by C++17). llvm::Value *IdxPre = (E->getLHS() == E->getIdx()) ? EmitScalarExpr(E->getIdx()) : nullptr; + bool SignedIndices = false; auto EmitIdxAfterBase = [&, IdxPre](bool Promote) -> llvm::Value * { auto *Idx = IdxPre; if (E->getLHS() != E->getIdx()) { @@ -3078,6 +3090,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, QualType IdxTy = E->getIdx()->getType(); bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType(); + SignedIndices |= IdxSigned; if (SanOpts.has(SanitizerKind::ArrayBounds)) EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed); @@ -3113,7 +3126,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, QualType EltType = LV.getType()->castAs()->getElementType(); Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true, - E->getExprLoc()); + SignedIndices, E->getExprLoc()); return MakeAddrLValue(Addr, EltType, LV.getBaseInfo()); } @@ -3142,7 +3155,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, Addr = emitArraySubscriptGEP(*this, Addr, Idx, vla->getElementType(), !getLangOpts().isSignedOverflowDefined(), - E->getExprLoc()); + SignedIndices, E->getExprLoc()); } else if (const ObjCObjectType *OIT = E->getType()->getAs()){ // Indexing over an interface, as in "NSString *P; P[4];" @@ -3167,8 +3180,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, // Do the GEP. CharUnits EltAlign = getArrayElementAlign(Addr.getAlignment(), Idx, InterfaceSize); - llvm::Value *EltPtr = emitArraySubscriptGEP( - *this, Addr.getPointer(), ScaledIdx, false, E->getExprLoc()); + llvm::Value *EltPtr = + emitArraySubscriptGEP(*this, Addr.getPointer(), ScaledIdx, false, + SignedIndices, E->getExprLoc()); Addr = Address(EltPtr, EltAlign); // Cast back. @@ -3190,11 +3204,10 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, auto *Idx = EmitIdxAfterBase(/*Promote*/true); // Propagate the alignment from the array itself to the result. - Addr = emitArraySubscriptGEP(*this, ArrayLV.getAddress(), - {CGM.getSize(CharUnits::Zero()), Idx}, - E->getType(), - !getLangOpts().isSignedOverflowDefined(), - E->getExprLoc()); + Addr = emitArraySubscriptGEP( + *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx}, + E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices, + E->getExprLoc()); BaseInfo = ArrayLV.getBaseInfo(); } else { // The base must be a pointer; emit it with an estimate of its alignment. @@ -3202,7 +3215,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, auto *Idx = EmitIdxAfterBase(/*Promote*/true); Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(), !getLangOpts().isSignedOverflowDefined(), - E->getExprLoc()); + SignedIndices, E->getExprLoc()); } LValue LV = MakeAddrLValue(Addr, E->getType(), BaseInfo); @@ -3375,7 +3388,7 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, Idx = Builder.CreateNSWMul(Idx, NumElements); EltPtr = emitArraySubscriptGEP(*this, Base, Idx, VLA->getElementType(), !getLangOpts().isSignedOverflowDefined(), - E->getExprLoc()); + /*SignedIndices=*/false, E->getExprLoc()); } else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) { // If this is A[i] where A is an array, the frontend will have decayed the // base to be a ArrayToPointerDecay implicit cast. While correct, it is @@ -3395,14 +3408,14 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, EltPtr = emitArraySubscriptGEP( *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx}, ResultExprTy, !getLangOpts().isSignedOverflowDefined(), - E->getExprLoc()); + /*SignedIndices=*/false, E->getExprLoc()); BaseInfo = ArrayLV.getBaseInfo(); } else { Address Base = emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, BaseTy, ResultExprTy, IsLowerBound); EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy, !getLangOpts().isSignedOverflowDefined(), - E->getExprLoc()); + /*SignedIndices=*/false, E->getExprLoc()); } return MakeAddrLValue(EltPtr, ResultExprTy, BaseInfo); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index f9d1fe468748..43c86495f3d3 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1851,6 +1851,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, llvm::Value *input; int amount = (isInc ? 1 : -1); + bool signedIndex = !isInc; if (const AtomicType *atomicTy = type->getAs()) { type = atomicTy->getValueType(); @@ -1940,8 +1941,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, numElts, "vla.inc"); else - value = CGF.EmitCheckedInBoundsGEP(value, numElts, E->getExprLoc(), - "vla.inc"); + value = CGF.EmitCheckedInBoundsGEP(value, numElts, signedIndex, + E->getExprLoc(), "vla.inc"); // Arithmetic on function pointers (!) is just +-1. } else if (type->isFunctionType()) { @@ -1951,8 +1952,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, amt, "incdec.funcptr"); else - value = CGF.EmitCheckedInBoundsGEP(value, amt, E->getExprLoc(), - "incdec.funcptr"); + value = CGF.EmitCheckedInBoundsGEP(value, amt, signedIndex, + E->getExprLoc(), "incdec.funcptr"); value = Builder.CreateBitCast(value, input->getType()); // For everything else, we can just do a simple increment. @@ -1961,8 +1962,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, amt, "incdec.ptr"); else - value = CGF.EmitCheckedInBoundsGEP(value, amt, E->getExprLoc(), - "incdec.ptr"); + value = CGF.EmitCheckedInBoundsGEP(value, amt, signedIndex, + E->getExprLoc(), "incdec.ptr"); } // Vector increment/decrement. @@ -2043,8 +2044,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, sizeValue, "incdec.objptr"); else - value = CGF.EmitCheckedInBoundsGEP(value, sizeValue, E->getExprLoc(), - "incdec.objptr"); + value = CGF.EmitCheckedInBoundsGEP(value, sizeValue, signedIndex, + E->getExprLoc(), "incdec.objptr"); value = Builder.CreateBitCast(value, input->getType()); } @@ -2661,13 +2662,15 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, std::swap(pointerOperand, indexOperand); } + bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType(); + bool mayHaveNegativeGEPIndex = isSigned || isSubtraction; + unsigned width = cast(index->getType())->getBitWidth(); auto &DL = CGF.CGM.getDataLayout(); auto PtrTy = cast(pointer->getType()); if (width != DL.getTypeSizeInBits(PtrTy)) { // Zero-extend or sign-extend the pointer value according to // whether the index is signed or not. - bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType(); index = CGF.Builder.CreateIntCast(index, DL.getIntPtrType(PtrTy), isSigned, "idx.ext"); } @@ -2711,8 +2714,9 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr"); } else { index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index"); - pointer = CGF.EmitCheckedInBoundsGEP(pointer, index, op.E->getExprLoc(), - "add.ptr"); + pointer = + CGF.EmitCheckedInBoundsGEP(pointer, index, mayHaveNegativeGEPIndex, + op.E->getExprLoc(), "add.ptr"); } return pointer; } @@ -2729,8 +2733,8 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, if (CGF.getLangOpts().isSignedOverflowDefined()) return CGF.Builder.CreateGEP(pointer, index, "add.ptr"); - return CGF.EmitCheckedInBoundsGEP(pointer, index, op.E->getExprLoc(), - "add.ptr"); + return CGF.EmitCheckedInBoundsGEP(pointer, index, mayHaveNegativeGEPIndex, + op.E->getExprLoc(), "add.ptr"); } // Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and @@ -3848,6 +3852,7 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue( Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr, ArrayRef IdxList, + bool SignedIndices, SourceLocation Loc, const Twine &Name) { Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name); @@ -3905,7 +3910,7 @@ Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr, auto *ResultAndOverflow = Builder.CreateCall( (Opcode == BO_Add) ? SAddIntrinsic : SMulIntrinsic, {LHS, RHS}); OffsetOverflows = Builder.CreateOr( - OffsetOverflows, Builder.CreateExtractValue(ResultAndOverflow, 1)); + Builder.CreateExtractValue(ResultAndOverflow, 1), OffsetOverflows); return Builder.CreateExtractValue(ResultAndOverflow, 0); }; @@ -3951,12 +3956,18 @@ Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr, // 1) The total offset doesn't overflow, and // 2) The sign of the difference between the computed address and the base // pointer matches the sign of the total offset. - llvm::Value *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr); - llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr); - auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero); - llvm::Value *ValidGEP = Builder.CreateAnd( - Builder.CreateNot(OffsetOverflows), - Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid)); + llvm::Value *ValidGEP; + auto *NoOffsetOverflow = Builder.CreateNot(OffsetOverflows); + auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr); + if (SignedIndices) { + auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero); + llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr); + ValidGEP = Builder.CreateAnd( + Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid), + NoOffsetOverflow); + } else { + ValidGEP = Builder.CreateAnd(PosOrZeroValid, NoOffsetOverflow); + } llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)}; // Pass the computed GEP to the runtime to avoid emitting poisoned arguments. diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 468838e56e38..8d83255ac139 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -6327,7 +6327,7 @@ bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) { } } - // If we are in target mode we do not emit any global (declare target is not + // If we are in target mode, we do not emit any global (declare target is not // implemented yet). Therefore we signal that GD was processed in this case. return true; } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 42ffd0d3efcc..831eedf9e478 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2550,9 +2550,11 @@ public: RValue EmitCoawaitExpr(const CoawaitExpr &E, AggValueSlot aggSlot = AggValueSlot::ignored(), bool ignoreResult = false); + LValue EmitCoawaitLValue(const CoawaitExpr *E); RValue EmitCoyieldExpr(const CoyieldExpr &E, AggValueSlot aggSlot = AggValueSlot::ignored(), bool ignoreResult = false); + LValue EmitCoyieldLValue(const CoyieldExpr *E); RValue EmitCoroutineIntrinsic(const CallExpr *E, unsigned int IID); void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false); @@ -3554,8 +3556,10 @@ public: /// Same as IRBuilder::CreateInBoundsGEP, but additionally emits a check to /// detect undefined behavior when the pointer overflow sanitizer is enabled. + /// \p SignedIndices indicates whether any of the GEP indices are signed. llvm::Value *EmitCheckedInBoundsGEP(llvm::Value *Ptr, ArrayRef IdxList, + bool SignedIndices, SourceLocation Loc, const Twine &Name = ""); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 77adf7b441a2..19a055075604 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1243,7 +1243,7 @@ void CodeGenModule::AddDependentLib(StringRef Lib) { /// \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 &Metadata, + SmallVectorImpl &Metadata, llvm::SmallPtrSet &Visited) { // Import this module's parent. if (Mod->Parent && Visited.insert(Mod->Parent).second) { @@ -1331,7 +1331,7 @@ 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 MetadataArgs; + SmallVector MetadataArgs; Visited.clear(); for (Module *M : LinkModules) if (Visited.insert(M).second) @@ -1340,9 +1340,9 @@ void CodeGenModule::EmitModuleLinkOptions() { LinkerOptionsMetadata.append(MetadataArgs.begin(), MetadataArgs.end()); // Add the linker options metadata flag. - getModule().addModuleFlag(llvm::Module::AppendUnique, "Linker Options", - llvm::MDNode::get(getLLVMContext(), - LinkerOptionsMetadata)); + auto *NMD = getModule().getOrInsertNamedMetadata("llvm.linker.options"); + for (auto *MD : LinkerOptionsMetadata) + NMD->addOperand(MD); } void CodeGenModule::EmitDeferred() { diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 0a71c635e8f0..59e56a6ba194 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -429,7 +429,7 @@ private: llvm::SmallPtrSet EmittedModuleInitializers; /// \brief A vector of metadata strings. - SmallVector LinkerOptionsMetadata; + SmallVector LinkerOptionsMetadata; /// @name Cache for Objective-C runtime types /// @{ @@ -1058,13 +1058,14 @@ public: void RefreshTypeCacheForClass(const CXXRecordDecl *Class); - /// \brief Appends Opts to the "Linker Options" metadata value. + /// \brief Appends Opts to the "llvm.linker.options" metadata value. void AppendLinkerOptions(StringRef Opts); /// \brief Appends a detect mismatch command to the linker options. void AddDetectMismatch(StringRef Name, StringRef Value); - /// \brief Appends a dependent lib to the "Linker Options" metadata value. + /// \brief Appends a dependent lib to the "llvm.linker.options" metadata + /// value. void AddDependentLib(StringRef Lib); llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD); diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 6d3dbb5b5204..bd4e894d6504 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -980,6 +980,9 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, DepTarget = Args.MakeArgString(llvm::sys::path::filename(P)); } + if (!A->getOption().matches(options::OPT_MD) && !A->getOption().matches(options::OPT_MMD)) { + CmdArgs.push_back("-w"); + } CmdArgs.push_back("-MT"); SmallString<128> Quoted; QuoteTarget(DepTarget, Quoted); diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 2ef6516e02ee..39da87cf9988 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -310,6 +310,8 @@ template <> struct MappingTraits { IO.mapOptional("BreakBeforeBinaryOperators", Style.BreakBeforeBinaryOperators); IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); + IO.mapOptional("BreakBeforeInheritanceComma", + Style.BreakBeforeInheritanceComma); IO.mapOptional("BreakBeforeTernaryOperators", Style.BreakBeforeTernaryOperators); @@ -330,8 +332,7 @@ template <> struct MappingTraits { IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals); IO.mapOptional("ColumnLimit", Style.ColumnLimit); IO.mapOptional("CommentPragmas", Style.CommentPragmas); - IO.mapOptional("BreakBeforeInheritanceComma", - Style.BreakBeforeInheritanceComma); + IO.mapOptional("CompactNamespaces", Style.CompactNamespaces); IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine", Style.ConstructorInitializerAllOnOneLineOrOnePerLine); IO.mapOptional("ConstructorInitializerIndentWidth", @@ -410,6 +411,7 @@ template <> struct MappingTraits { IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch); IO.mapOptional("BeforeElse", Wrapping.BeforeElse); IO.mapOptional("IndentBraces", Wrapping.IndentBraces); + IO.mapOptional("SplitEmptyFunctionBody", Wrapping.SplitEmptyFunctionBody); } }; @@ -485,7 +487,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) { return Style; FormatStyle Expanded = Style; Expanded.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false}; + false, false, false, false, false, true}; switch (Style.BreakBeforeBraces) { case FormatStyle::BS_Linux: Expanded.BraceWrapping.AfterClass = true; @@ -498,6 +500,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) { Expanded.BraceWrapping.AfterFunction = true; Expanded.BraceWrapping.AfterStruct = true; Expanded.BraceWrapping.AfterUnion = true; + Expanded.BraceWrapping.SplitEmptyFunctionBody = false; break; case FormatStyle::BS_Stroustrup: Expanded.BraceWrapping.AfterFunction = true; @@ -517,7 +520,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) { break; case FormatStyle::BS_GNU: Expanded.BraceWrapping = {true, true, true, true, true, true, - true, true, true, true, true}; + true, true, true, true, true, true}; break; case FormatStyle::BS_WebKit: Expanded.BraceWrapping.AfterFunction = true; @@ -548,19 +551,20 @@ FormatStyle getLLVMStyle() { LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; LLVMStyle.AlwaysBreakBeforeMultilineStrings = false; LLVMStyle.AlwaysBreakTemplateDeclarations = false; - LLVMStyle.BinPackParameters = true; LLVMStyle.BinPackArguments = true; + LLVMStyle.BinPackParameters = true; LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; LLVMStyle.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false}; + false, false, false, false, false, true}; LLVMStyle.BreakAfterJavaFieldAnnotations = false; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakBeforeInheritanceComma = false; LLVMStyle.BreakStringLiterals = true; LLVMStyle.ColumnLimit = 80; LLVMStyle.CommentPragmas = "^ IWYU pragma:"; + LLVMStyle.CompactNamespaces = false; LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false; LLVMStyle.ConstructorInitializerIndentWidth = 4; LLVMStyle.ContinuationIndentWidth = 4; diff --git a/lib/Format/NamespaceEndCommentsFixer.cpp b/lib/Format/NamespaceEndCommentsFixer.cpp index 88cf123c1899..1bbb41f757ae 100644 --- a/lib/Format/NamespaceEndCommentsFixer.cpp +++ b/lib/Format/NamespaceEndCommentsFixer.cpp @@ -107,6 +107,24 @@ void updateEndComment(const FormatToken *RBraceTok, StringRef EndCommentText, << llvm::toString(std::move(Err)) << "\n"; } } + +const FormatToken * +getNamespaceToken(const AnnotatedLine *line, + const SmallVectorImpl &AnnotatedLines) { + if (!line->Affected || line->InPPDirective || !line->startsWith(tok::r_brace)) + return nullptr; + size_t StartLineIndex = line->MatchingOpeningBlockLineIndex; + if (StartLineIndex == UnwrappedLine::kInvalidIndex) + return nullptr; + assert(StartLineIndex < AnnotatedLines.size()); + const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First; + // Detect "(inline)? namespace" in the beginning of a line. + if (NamespaceTok->is(tok::kw_inline)) + NamespaceTok = NamespaceTok->getNextNonComment(); + if (!NamespaceTok || NamespaceTok->isNot(tok::kw_namespace)) + return nullptr; + return NamespaceTok; +} } // namespace NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env, @@ -120,20 +138,14 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze( AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(), AnnotatedLines.end()); tooling::Replacements Fixes; + std::string AllNamespaceNames = ""; + size_t StartLineIndex = SIZE_MAX; + unsigned int CompactedNamespacesCount = 0; for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) { - if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective || - !AnnotatedLines[I]->startsWith(tok::r_brace)) - continue; const AnnotatedLine *EndLine = AnnotatedLines[I]; - size_t StartLineIndex = EndLine->MatchingOpeningBlockLineIndex; - if (StartLineIndex == UnwrappedLine::kInvalidIndex) - continue; - assert(StartLineIndex < E); - const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First; - // Detect "(inline)? namespace" in the beginning of a line. - if (NamespaceTok->is(tok::kw_inline)) - NamespaceTok = NamespaceTok->getNextNonComment(); - if (!NamespaceTok || NamespaceTok->isNot(tok::kw_namespace)) + const FormatToken *NamespaceTok = + getNamespaceToken(EndLine, AnnotatedLines); + if (!NamespaceTok) continue; FormatToken *RBraceTok = EndLine->First; if (RBraceTok->Finalized) @@ -145,6 +157,27 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze( if (RBraceTok->Next && RBraceTok->Next->is(tok::semi)) { EndCommentPrevTok = RBraceTok->Next; } + if (StartLineIndex == SIZE_MAX) + StartLineIndex = EndLine->MatchingOpeningBlockLineIndex; + std::string NamespaceName = computeName(NamespaceTok); + if (Style.CompactNamespaces) { + if ((I + 1 < E) && + getNamespaceToken(AnnotatedLines[I + 1], AnnotatedLines) && + StartLineIndex - CompactedNamespacesCount - 1 == + AnnotatedLines[I + 1]->MatchingOpeningBlockLineIndex && + !AnnotatedLines[I + 1]->First->Finalized) { + if (hasEndComment(EndCommentPrevTok)) { + // remove end comment, it will be merged in next one + updateEndComment(EndCommentPrevTok, std::string(), SourceMgr, &Fixes); + } + CompactedNamespacesCount++; + AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames; + continue; + } + NamespaceName += std::move(AllNamespaceNames); + CompactedNamespacesCount = 0; + AllNamespaceNames = std::string(); + } // The next token in the token stream after the place where the end comment // token must be. This is either the next token on the current line or the // first token on the next line. @@ -156,17 +189,16 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze( bool AddNewline = EndCommentNextTok && EndCommentNextTok->NewlinesBefore == 0 && EndCommentNextTok->isNot(tok::eof); - const std::string NamespaceName = computeName(NamespaceTok); const std::string EndCommentText = computeEndCommentText(NamespaceName, AddNewline); if (!hasEndComment(EndCommentPrevTok)) { bool isShort = I - StartLineIndex <= kShortNamespaceMaxLines + 1; if (!isShort) addEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes); - continue; - } - if (!validEndComment(EndCommentPrevTok, NamespaceName)) + } else if (!validEndComment(EndCommentPrevTok, NamespaceName)) { updateEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes); + } + StartLineIndex = SIZE_MAX; } return Fixes; } diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp index 01504da0a29b..7f644651a6ab 100644 --- a/lib/Format/UnwrappedLineFormatter.cpp +++ b/lib/Format/UnwrappedLineFormatter.cpp @@ -66,6 +66,13 @@ public: Indent += Offset; } + /// \brief Update the indent state given that \p Line indent should be + /// skipped. + void skipLine(const AnnotatedLine &Line) { + while (IndentForLevel.size() <= Line.Level) + IndentForLevel.push_back(Indent); + } + /// \brief Update the level indent to adapt to the given \p Line. /// /// When a line is not formatted, we move the subsequent lines on the same @@ -127,12 +134,31 @@ private: unsigned Indent = 0; }; +bool isNamespaceDeclaration(const AnnotatedLine *Line) { + const FormatToken *NamespaceTok = Line->First; + // Detect "(inline)? namespace" in the beginning of a line. + if (NamespaceTok->is(tok::kw_inline)) + NamespaceTok = NamespaceTok->getNextNonComment(); + return NamespaceTok && NamespaceTok->is(tok::kw_namespace); +} + +bool isEndOfNamespace(const AnnotatedLine *Line, + const SmallVectorImpl &AnnotatedLines) { + if (!Line->startsWith(tok::r_brace)) + return false; + size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex; + if (StartLineIndex == UnwrappedLine::kInvalidIndex) + return false; + assert(StartLineIndex < AnnotatedLines.size()); + return isNamespaceDeclaration(AnnotatedLines[StartLineIndex]); +} + class LineJoiner { public: LineJoiner(const FormatStyle &Style, const AdditionalKeywords &Keywords, const SmallVectorImpl &Lines) - : Style(Style), Keywords(Keywords), End(Lines.end()), - Next(Lines.begin()) {} + : Style(Style), Keywords(Keywords), End(Lines.end()), Next(Lines.begin()), + AnnotatedLines(Lines) {} /// \brief Returns the next line, merging multiple lines into one if possible. const AnnotatedLine *getNextMergedLine(bool DryRun, @@ -142,7 +168,7 @@ public: const AnnotatedLine *Current = *Next; IndentTracker.nextLine(*Current); unsigned MergedLines = - tryFitMultipleLinesInOne(IndentTracker.getIndent(), Next, End); + tryFitMultipleLinesInOne(IndentTracker, Next, End); if (MergedLines > 0 && Style.ColumnLimit == 0) // Disallow line merging if there is a break at the start of one of the // input lines. @@ -159,9 +185,11 @@ public: private: /// \brief Calculates how many lines can be merged into 1 starting at \p I. unsigned - tryFitMultipleLinesInOne(unsigned Indent, + tryFitMultipleLinesInOne(LevelIndentTracker &IndentTracker, SmallVectorImpl::const_iterator I, SmallVectorImpl::const_iterator E) { + const unsigned Indent = IndentTracker.getIndent(); + // Can't join the last line with anything. if (I + 1 == E) return 0; @@ -186,6 +214,12 @@ private: ? 0 : Limit - TheLine->Last->TotalLength; + if (TheLine->Last->is(TT_FunctionLBrace) && + TheLine->First == TheLine->Last && + !Style.BraceWrapping.SplitEmptyFunctionBody && + I[1]->First->is(tok::r_brace)) + return tryMergeSimpleBlock(I, E, Limit); + // FIXME: TheLine->Level != 0 might or might not be the right check to do. // If necessary, change to something smarter. bool MergeShortFunctions = @@ -195,6 +229,38 @@ private: (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline && TheLine->Level != 0); + if (Style.CompactNamespaces) { + if (isNamespaceDeclaration(TheLine)) { + int i = 0; + unsigned closingLine = TheLine->MatchingOpeningBlockLineIndex - 1; + for (; I + 1 + i != E && isNamespaceDeclaration(I[i + 1]) && + closingLine == I[i + 1]->MatchingOpeningBlockLineIndex && + I[i + 1]->Last->TotalLength < Limit; + i++, closingLine--) { + // No extra indent for compacted namespaces + IndentTracker.skipLine(*I[i + 1]); + + Limit -= I[i + 1]->Last->TotalLength; + } + return i; + } + + if (isEndOfNamespace(TheLine, AnnotatedLines)) { + int i = 0; + unsigned openingLine = TheLine->MatchingOpeningBlockLineIndex - 1; + for (; I + 1 + i != E && isEndOfNamespace(I[i + 1], AnnotatedLines) && + openingLine == I[i + 1]->MatchingOpeningBlockLineIndex; + i++, openingLine--) { + // No space between consecutive braces + I[i + 1]->First->SpacesRequiredBefore = !I[i]->Last->is(tok::r_brace); + + // Indent like the outer-most namespace + IndentTracker.nextLine(*I[i + 1]); + } + return i; + } + } + if (TheLine->Last->is(TT_FunctionLBrace) && TheLine->First != TheLine->Last) { return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0; @@ -215,7 +281,10 @@ private: Limit -= 2; unsigned MergedLines = 0; - if (MergeShortFunctions) { + if (MergeShortFunctions || + (Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty && + I[1]->First == I[1]->Last && I + 2 != E && + I[2]->First->is(tok::r_brace))) { MergedLines = tryMergeSimpleBlock(I + 1, E, Limit); // If we managed to merge the block, count the function header, which is // on a separate line. @@ -449,6 +518,7 @@ private: const SmallVectorImpl::const_iterator End; SmallVectorImpl::const_iterator Next; + const SmallVectorImpl &AnnotatedLines; }; static void markFinalized(FormatToken *Tok) { diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index eda7ef36434d..27436dda67a7 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -492,6 +492,11 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, nextToken(); Line->Level = InitialLevel; Line->MatchingOpeningBlockLineIndex = OpeningLineIndex; + if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) { + // Update the opening line to add the forward reference as well + (*CurrentLines)[OpeningLineIndex].MatchingOpeningBlockLineIndex = + CurrentLines->size() - 1; + } } static bool isGoogScope(const UnwrappedLine &Line) { diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h index 6be4af262276..50df59d09641 100644 --- a/lib/Format/WhitespaceManager.h +++ b/lib/Format/WhitespaceManager.h @@ -43,6 +43,10 @@ public: /// \brief Replaces the whitespace in front of \p Tok. Only call once for /// each \c AnnotatedToken. + /// + /// \p StartOfTokenColumn is the column at which the token will start after + /// this replacement. It is needed for determining how \p Spaces is turned + /// into tabs and spaces for some format styles. void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces, unsigned StartOfTokenColumn, bool InPPDirective = false); diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 720baa5e0f7a..7dc475e26f76 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -142,7 +142,7 @@ std::unique_ptr clang::CreateASTDumper(StringRef FilterString, bool DumpDecls, bool Deserialize, bool DumpLookups) { - assert((DumpDecls || DumpLookups) && "nothing to dump"); + assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump"); return llvm::make_unique(nullptr, Deserialize ? ASTPrinter::DumpFull : DumpDecls ? ASTPrinter::Dump : diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index bb635b7ad714..1667af2d12bb 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -649,8 +649,14 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.NoUseJumpTables = Args.hasArg(OPT_fno_jump_tables); Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ); - const Arg *A = Args.getLastArg(OPT_flto, OPT_flto_EQ); - Opts.EmitSummaryIndex = A && A->containsValue("thin"); + Opts.EmitSummaryIndex = false; + if (Arg *A = Args.getLastArg(OPT_flto_EQ)) { + StringRef S = A->getValue(); + if (S == "thin") + Opts.EmitSummaryIndex = true; + else if (S != "full") + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << S; + } Opts.LTOUnit = Args.hasFlag(OPT_flto_unit, OPT_fno_lto_unit, false); if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) { if (IK.getLanguage() != InputKind::LLVM_IR) diff --git a/lib/Index/IndexDecl.cpp b/lib/Index/IndexDecl.cpp index 870b4e4fe825..2162c039c48b 100644 --- a/lib/Index/IndexDecl.cpp +++ b/lib/Index/IndexDecl.cpp @@ -293,6 +293,12 @@ public: return true; } + bool VisitDecompositionDecl(const DecompositionDecl *D) { + for (const auto *Binding : D->bindings()) + TRY_DECL(Binding, IndexCtx.handleDecl(Binding)); + return Base::VisitDecompositionDecl(D); + } + bool VisitFieldDecl(const FieldDecl *D) { SmallVector Relations; gatherTemplatePseudoOverrides(D, Relations); @@ -682,6 +688,13 @@ public: bool VisitImportDecl(const ImportDecl *D) { return IndexCtx.importedModule(D); } + + bool VisitStaticAssertDecl(const StaticAssertDecl *D) { + IndexCtx.indexBody(D->getAssertExpr(), + dyn_cast(D->getDeclContext()), + D->getLexicalDeclContext()); + return true; + } }; } // anonymous namespace diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp index 0b20970acc3b..bf358a372149 100644 --- a/lib/Index/IndexSymbol.cpp +++ b/lib/Index/IndexSymbol.cpp @@ -301,6 +301,10 @@ SymbolInfo index::getSymbolInfo(const Decl *D) { Info.Kind = SymbolKind::TypeAlias; Info.Lang = SymbolLanguage::CXX; break; + case Decl::Binding: + Info.Kind = SymbolKind::Variable; + Info.Lang = SymbolLanguage::CXX; + break; default: break; } diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp index 1c1979d8e83d..a201d1659073 100644 --- a/lib/Lex/MacroArgs.cpp +++ b/lib/Lex/MacroArgs.cpp @@ -44,20 +44,22 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI, // Otherwise, use the best fit. ClosestMatch = (*Entry)->NumUnexpArgTokens; } - + MacroArgs *Result; if (!ResultEnt) { // Allocate memory for a MacroArgs object with the lexer tokens at the end. - Result = (MacroArgs*)malloc(sizeof(MacroArgs) + - UnexpArgTokens.size() * sizeof(Token)); + Result = (MacroArgs *)malloc(sizeof(MacroArgs) + + UnexpArgTokens.size() * sizeof(Token)); // Construct the MacroArgs object. - new (Result) MacroArgs(UnexpArgTokens.size(), VarargsElided); + new (Result) + MacroArgs(UnexpArgTokens.size(), VarargsElided, MI->getNumArgs()); } else { Result = *ResultEnt; // Unlink this node from the preprocessors singly linked list. *ResultEnt = Result->ArgCache; Result->NumUnexpArgTokens = UnexpArgTokens.size(); Result->VarargsElided = VarargsElided; + Result->NumMacroArgs = MI->getNumArgs(); } // Copy the actual unexpanded tokens to immediately after the result ptr. @@ -298,12 +300,10 @@ const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo, Preprocessor &PP, SourceLocation ExpansionLocStart, SourceLocation ExpansionLocEnd) { - assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!"); - if (StringifiedArgs.empty()) { - StringifiedArgs.resize(getNumArguments()); - memset((void*)&StringifiedArgs[0], 0, - sizeof(StringifiedArgs[0])*getNumArguments()); - } + assert(ArgNo < getNumMacroArguments() && "Invalid argument number!"); + if (StringifiedArgs.empty()) + StringifiedArgs.resize(getNumMacroArguments(), {}); + if (StringifiedArgs[ArgNo].isNot(tok::string_literal)) StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP, /*Charify=*/false, diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index b9349dc06bff..83c3bd27596c 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4542,8 +4542,10 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext) { if (!SS.getScopeRep() || !CodeCompleter) return; - - DeclContext *Ctx = computeDeclContext(SS, EnteringContext); + + // Always pretend to enter a context to ensure that a dependent type + // resolves to a dependent record. + DeclContext *Ctx = computeDeclContext(SS, /*EnteringContext=*/true); if (!Ctx) return; @@ -4573,7 +4575,9 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, Results.ExitScope(); CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer); + LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer, + /*IncludeGlobalScope=*/true, + /*IncludeDependentBases=*/true); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp index 06ae66076e8a..b05c0998d3dd 100644 --- a/lib/Sema/SemaCoroutine.cpp +++ b/lib/Sema/SemaCoroutine.cpp @@ -470,11 +470,11 @@ static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc, return ScopeInfo; } -static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc, - StringRef Keyword) { - if (!checkCoroutineContext(S, KWLoc, Keyword)) +bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc, + StringRef Keyword) { + if (!checkCoroutineContext(*this, KWLoc, Keyword)) return false; - auto *ScopeInfo = S.getCurFunction(); + auto *ScopeInfo = getCurFunction(); assert(ScopeInfo->CoroutinePromise); // If we have existing coroutine statements then we have already built @@ -484,24 +484,24 @@ static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc, ScopeInfo->setNeedsCoroutineSuspends(false); - auto *Fn = cast(S.CurContext); + auto *Fn = cast(CurContext); SourceLocation Loc = Fn->getLocation(); // Build the initial suspend point auto buildSuspends = [&](StringRef Name) mutable -> StmtResult { ExprResult Suspend = - buildPromiseCall(S, ScopeInfo->CoroutinePromise, Loc, Name, None); + buildPromiseCall(*this, ScopeInfo->CoroutinePromise, Loc, Name, None); if (Suspend.isInvalid()) return StmtError(); - Suspend = buildOperatorCoawaitCall(S, SC, Loc, Suspend.get()); + Suspend = buildOperatorCoawaitCall(*this, SC, Loc, Suspend.get()); if (Suspend.isInvalid()) return StmtError(); - Suspend = S.BuildResolvedCoawaitExpr(Loc, Suspend.get(), - /*IsImplicit*/ true); - Suspend = S.ActOnFinishFullExpr(Suspend.get()); + Suspend = BuildResolvedCoawaitExpr(Loc, Suspend.get(), + /*IsImplicit*/ true); + Suspend = ActOnFinishFullExpr(Suspend.get()); if (Suspend.isInvalid()) { - S.Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required) + Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required) << ((Name == "initial_suspend") ? 0 : 1); - S.Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword; + Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword; return StmtError(); } return cast(Suspend.get()); @@ -521,7 +521,7 @@ static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc, } ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) { - if (!actOnCoroutineBodyStart(*this, S, Loc, "co_await")) { + if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) { CorrectDelayedTyposInExpr(E); return ExprError(); } @@ -613,7 +613,7 @@ ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *E, } ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) { - if (!actOnCoroutineBodyStart(*this, S, Loc, "co_yield")) { + if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) { CorrectDelayedTyposInExpr(E); return ExprError(); } @@ -658,14 +658,15 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) { if (RSS.IsInvalid) return ExprError(); - Expr *Res = new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1], - RSS.Results[2], RSS.OpaqueValue); + Expr *Res = + new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1], + RSS.Results[2], RSS.OpaqueValue); return Res; } StmtResult Sema::ActOnCoreturnStmt(Scope *S, SourceLocation Loc, Expr *E) { - if (!actOnCoroutineBodyStart(*this, S, Loc, "co_return")) { + if (!ActOnCoroutineBodyStart(S, Loc, "co_return")) { CorrectDelayedTyposInExpr(E); return StmtError(); } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 6c492fac9eb9..b43642f5493b 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -313,8 +313,8 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range, /// \returns true if IdxExpr is a valid index. template static bool checkFunctionOrMethodParameterIndex( - Sema &S, const Decl *D, const AttrInfo& Attr, - unsigned AttrArgNum, const Expr *IdxExpr, uint64_t &Idx) { + Sema &S, const Decl *D, const AttrInfo &Attr, unsigned AttrArgNum, + const Expr *IdxExpr, uint64_t &Idx, bool AllowImplicitThis = false) { assert(isFunctionOrMethodOrBlock(D)); // In C++ the implicit 'this' function parameter also counts. @@ -341,7 +341,7 @@ static bool checkFunctionOrMethodParameterIndex( return false; } Idx--; // Convert to zero-based. - if (HasImplicitThisParam) { + if (HasImplicitThisParam && !AllowImplicitThis) { if (Idx == 0) { S.Diag(getAttrLoc(Attr), diag::err_attribute_invalid_implicit_this_argument) @@ -4604,14 +4604,16 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, static void handleXRayLogArgsAttr(Sema &S, Decl *D, const AttributeList &Attr) { uint64_t ArgCount; + if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, Attr.getArgAsExpr(0), - ArgCount)) + ArgCount, + true /* AllowImplicitThis*/)) return; // ArgCount isn't a parameter index [0;n), it's a count [1;n] - hence + 1. D->addAttr(::new (S.Context) - XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount, - Attr.getAttributeSpellingListIndex())); + XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount, + Attr.getAttributeSpellingListIndex())); } //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0f8f5c253ac6..75a6903392ea 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -12057,11 +12057,17 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, } break; case UO_Extension: - case UO_Coawait: resultType = Input.get()->getType(); VK = Input.get()->getValueKind(); OK = Input.get()->getObjectKind(); break; + case UO_Coawait: + // It's unnessesary to represent the pass-through operator co_await in the + // AST; just return the input expression instead. + assert(!Input.get()->getType()->isDependentType() && + "the co_await expression must be non-dependant before " + "building operator co_await"); + return Input; } if (resultType.isNull() || Input.isInvalid()) return ExprError(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 00a4b39f1423..a9ff21bc41ab 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -189,12 +189,15 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // have one) and, if that fails to find a match, in the scope (if // we're allowed to look there). Found.clear(); - if (Step == 0 && LookupCtx) + if (Step == 0 && LookupCtx) { + if (RequireCompleteDeclContext(SS, LookupCtx)) + return nullptr; LookupQualifiedName(Found, LookupCtx); - else if (Step == 1 && LookInScope && S) + } else if (Step == 1 && LookInScope && S) { LookupName(Found, S); - else + } else { continue; + } // FIXME: Should we be suppressing ambiguities here? if (Found.isAmbiguous()) diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index a6239283b47b..d6b70610d461 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -1492,6 +1492,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, bool ExplicitResultType; CleanupInfo LambdaCleanup; bool ContainsUnexpandedParameterPack; + bool IsGenericLambda; { CallOperator = LSI->CallOperator; Class = LSI->Lambda; @@ -1500,7 +1501,8 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, ExplicitResultType = !LSI->HasImplicitReturnType; LambdaCleanup = LSI->Cleanup; ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack; - + IsGenericLambda = Class->isGenericLambda(); + CallOperator->setLexicalDeclContext(Class); Decl *TemplateOrNonTemplateCallOperatorDecl = CallOperator->getDescribedFunctionTemplate() @@ -1520,8 +1522,13 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, bool IsImplicit = I >= LSI->NumExplicitCaptures; // Warn about unused explicit captures. - if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) - DiagnoseUnusedLambdaCapture(From); + if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) { + // Initialized captures that are non-ODR used may not be eliminated. + bool NonODRUsedInitCapture = + IsGenericLambda && From.isNonODRUsed() && From.getInitExpr(); + if (!NonODRUsedInitCapture) + DiagnoseUnusedLambdaCapture(From); + } // Handle 'this' capture. if (From.isThisCapture()) { @@ -1568,8 +1575,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, // same parameter and return types as the closure type's function call // operator. // FIXME: Fix generic lambda to block conversions. - if (getLangOpts().Blocks && getLangOpts().ObjC1 && - !Class->isGenericLambda()) + if (getLangOpts().Blocks && getLangOpts().ObjC1 && !IsGenericLambda) addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator); // Finalize the lambda class. diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 151b89ab8d2a..eed10b077eb8 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1989,11 +1989,11 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, return StmtError(); } - // Coroutines: 'for co_await' implicitly co_awaits its range. - if (CoawaitLoc.isValid()) { - ExprResult Coawait = ActOnCoawaitExpr(S, CoawaitLoc, Range); - if (Coawait.isInvalid()) return StmtError(); - Range = Coawait.get(); + // Build the coroutine state immediately and not later during template + // instantiation + if (!CoawaitLoc.isInvalid()) { + if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await")) + return StmtError(); } // Build auto && __range = range-init @@ -2031,16 +2031,12 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, /// BeginExpr and EndExpr are set and FRS_Success is returned on success; /// CandidateSet and BEF are set and some non-success value is returned on /// failure. -static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, - Expr *BeginRange, Expr *EndRange, - QualType RangeType, - VarDecl *BeginVar, - VarDecl *EndVar, - SourceLocation ColonLoc, - OverloadCandidateSet *CandidateSet, - ExprResult *BeginExpr, - ExprResult *EndExpr, - BeginEndFunction *BEF) { +static Sema::ForRangeStatus +BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange, + QualType RangeType, VarDecl *BeginVar, VarDecl *EndVar, + SourceLocation ColonLoc, SourceLocation CoawaitLoc, + OverloadCandidateSet *CandidateSet, ExprResult *BeginExpr, + ExprResult *EndExpr, BeginEndFunction *BEF) { DeclarationNameInfo BeginNameInfo( &SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc); DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"), @@ -2087,6 +2083,15 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, << ColonLoc << BEF_begin << BeginRange->getType(); return RangeStatus; } + if (!CoawaitLoc.isInvalid()) { + // FIXME: getCurScope() should not be used during template instantiation. + // We should pick up the set of unqualified lookup results for operator + // co_await during the initial parse. + *BeginExpr = SemaRef.ActOnCoawaitExpr(SemaRef.getCurScope(), ColonLoc, + BeginExpr->get()); + if (BeginExpr->isInvalid()) + return Sema::FRS_DiagnosticIssued; + } if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc, diag::err_for_range_iter_deduction_failure)) { NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF); @@ -2206,8 +2211,12 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill // them in properly when we instantiate the loop. - if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) + if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) { + if (auto *DD = dyn_cast(LoopVar)) + for (auto *Binding : DD->bindings()) + Binding->setType(Context.DependentTy); LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy)); + } } else if (!BeginDeclStmt.get()) { SourceLocation RangeLoc = RangeVar->getLocation(); @@ -2249,6 +2258,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, // begin-expr is __range. BeginExpr = BeginRangeRef; + if (!CoawaitLoc.isInvalid()) { + BeginExpr = ActOnCoawaitExpr(S, ColonLoc, BeginExpr.get()); + if (BeginExpr.isInvalid()) + return StmtError(); + } if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc, diag::err_for_range_iter_deduction_failure)) { NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); @@ -2331,11 +2345,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, OverloadCandidateSet CandidateSet(RangeLoc, OverloadCandidateSet::CSK_Normal); BeginEndFunction BEFFailure; - ForRangeStatus RangeStatus = - BuildNonArrayForRange(*this, BeginRangeRef.get(), - EndRangeRef.get(), RangeType, - BeginVar, EndVar, ColonLoc, &CandidateSet, - &BeginExpr, &EndExpr, &BEFFailure); + ForRangeStatus RangeStatus = BuildNonArrayForRange( + *this, BeginRangeRef.get(), EndRangeRef.get(), RangeType, BeginVar, + EndVar, ColonLoc, CoawaitLoc, &CandidateSet, &BeginExpr, &EndExpr, + &BEFFailure); if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction && BEFFailure == BEF_begin) { @@ -2432,6 +2445,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get()); if (!IncrExpr.isInvalid() && CoawaitLoc.isValid()) + // FIXME: getCurScope() should not be used during template instantiation. + // We should pick up the set of unqualified lookup results for operator + // co_await during the initial parse. IncrExpr = ActOnCoawaitExpr(S, CoawaitLoc, IncrExpr.get()); if (!IncrExpr.isInvalid()) IncrExpr = ActOnFinishFullExpr(IncrExpr.get()); diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 94a8f609f57c..eeb0132c1690 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -9242,6 +9242,7 @@ void ASTReader::diagnoseOdrViolations() { // Used with err_module_odr_violation_mismatch_decl and // note_module_odr_violation_mismatch_decl + // This list should be the same Decl's as in ODRHash::isWhiteListedDecl enum { EndOfClass, PublicSpecifer, @@ -9250,6 +9251,9 @@ void ASTReader::diagnoseOdrViolations() { StaticAssert, Field, CXXMethod, + TypeAlias, + TypeDef, + Var, Other } FirstDiffType = Other, SecondDiffType = Other; @@ -9277,6 +9281,12 @@ void ASTReader::diagnoseOdrViolations() { return Field; case Decl::CXXMethod: return CXXMethod; + case Decl::TypeAlias: + return TypeAlias; + case Decl::Typedef: + return TypeDef; + case Decl::Var: + return Var; } }; @@ -9373,6 +9383,15 @@ void ASTReader::diagnoseOdrViolations() { MethodNumberParameters, MethodParameterType, MethodParameterName, + MethodParameterSingleDefaultArgument, + MethodParameterDifferentDefaultArgument, + TypedefName, + TypedefType, + VarName, + VarType, + VarSingleInitializer, + VarDifferentInitializer, + VarConstexpr, }; // These lambdas have the common portions of the ODR diagnostics. This @@ -9739,6 +9758,38 @@ void ASTReader::diagnoseOdrViolations() { ParameterMismatch = true; break; } + + const Expr *FirstInit = FirstParam->getInit(); + const Expr *SecondInit = SecondParam->getInit(); + if ((FirstInit == nullptr) != (SecondInit == nullptr)) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), + MethodParameterSingleDefaultArgument) + << FirstName << (I + 1) << (FirstInit == nullptr) + << (FirstInit ? FirstInit->getSourceRange() : SourceRange()); + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), + MethodParameterSingleDefaultArgument) + << SecondName << (I + 1) << (SecondInit == nullptr) + << (SecondInit ? SecondInit->getSourceRange() : SourceRange()); + ParameterMismatch = true; + break; + } + + if (FirstInit && SecondInit && + ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), + MethodParameterDifferentDefaultArgument) + << FirstName << (I + 1) << FirstInit->getSourceRange(); + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), + MethodParameterDifferentDefaultArgument) + << SecondName << (I + 1) << SecondInit->getSourceRange(); + ParameterMismatch = true; + break; + + } } if (ParameterMismatch) { @@ -9748,6 +9799,109 @@ void ASTReader::diagnoseOdrViolations() { break; } + case TypeAlias: + case TypeDef: { + TypedefNameDecl *FirstTD = cast(FirstDecl); + TypedefNameDecl *SecondTD = cast(SecondDecl); + auto FirstName = FirstTD->getDeclName(); + auto SecondName = SecondTD->getDeclName(); + if (FirstName != SecondName) { + ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(), + TypedefName) + << (FirstDiffType == TypeAlias) << FirstName; + ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(), + TypedefName) + << (FirstDiffType == TypeAlias) << SecondName; + Diagnosed = true; + break; + } + + QualType FirstType = FirstTD->getUnderlyingType(); + QualType SecondType = SecondTD->getUnderlyingType(); + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { + ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(), + TypedefType) + << (FirstDiffType == TypeAlias) << FirstName << FirstType; + ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(), + TypedefType) + << (FirstDiffType == TypeAlias) << SecondName << SecondType; + Diagnosed = true; + break; + } + break; + } + case Var: { + VarDecl *FirstVD = cast(FirstDecl); + VarDecl *SecondVD = cast(SecondDecl); + auto FirstName = FirstVD->getDeclName(); + auto SecondName = SecondVD->getDeclName(); + if (FirstName != SecondName) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarName) + << FirstName; + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarName) + << SecondName; + Diagnosed = true; + break; + } + + QualType FirstType = FirstVD->getType(); + QualType SecondType = SecondVD->getType(); + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarType) + << FirstName << FirstType; + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarType) + << SecondName << SecondType; + Diagnosed = true; + break; + } + + const Expr *FirstInit = FirstVD->getInit(); + const Expr *SecondInit = SecondVD->getInit(); + if ((FirstInit == nullptr) != (SecondInit == nullptr)) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarSingleInitializer) + << FirstName << (FirstInit == nullptr) + << (FirstInit ? FirstInit->getSourceRange(): SourceRange()); + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarSingleInitializer) + << SecondName << (SecondInit == nullptr) + << (SecondInit ? SecondInit->getSourceRange() : SourceRange()); + Diagnosed = true; + break; + } + + if (FirstInit && SecondInit && + ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarDifferentInitializer) + << FirstName << FirstInit->getSourceRange(); + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarDifferentInitializer) + << SecondName << SecondInit->getSourceRange(); + Diagnosed = true; + break; + } + + const bool FirstIsConstexpr = FirstVD->isConstexpr(); + const bool SecondIsConstexpr = SecondVD->isConstexpr(); + if (FirstIsConstexpr != SecondIsConstexpr) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarConstexpr) + << FirstName << FirstIsConstexpr; + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarConstexpr) + << SecondName << SecondIsConstexpr; + Diagnosed = true; + break; + } + break; + } } if (Diagnosed == true) diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 9c467055fe55..ed103e629216 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -216,30 +216,6 @@ namespace clang { TypedefNameForLinkage(nullptr), HasPendingBody(false), IsDeclMarkedUsed(false) {} - template static - void AddLazySpecializations(T *D, - SmallVectorImpl& IDs) { - if (IDs.empty()) - return; - - // FIXME: We should avoid this pattern of getting the ASTContext. - ASTContext &C = D->getASTContext(); - - auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations; - - if (auto &Old = LazySpecializations) { - IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]); - std::sort(IDs.begin(), IDs.end()); - IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); - } - - auto *Result = new (C) serialization::DeclID[1 + IDs.size()]; - *Result = IDs.size(); - std::copy(IDs.begin(), IDs.end(), Result + 1); - - LazySpecializations = Result; - } - template static Decl *getMostRecentDeclImpl(Redeclarable *D); static Decl *getMostRecentDeclImpl(...); @@ -268,7 +244,7 @@ namespace clang { void ReadFunctionDefinition(FunctionDecl *FD); void Visit(Decl *D); - void UpdateDecl(Decl *D, llvm::SmallVectorImpl&); + void UpdateDecl(Decl *D); static void setNextObjCCategory(ObjCCategoryDecl *Cat, ObjCCategoryDecl *Next) { @@ -1976,6 +1952,21 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { return Redecl; } +static DeclID *newDeclIDList(ASTContext &Context, DeclID *Old, + SmallVectorImpl &IDs) { + assert(!IDs.empty() && "no IDs to add to list"); + if (Old) { + IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]); + std::sort(IDs.begin(), IDs.end()); + IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); + } + + auto *Result = new (Context) DeclID[1 + IDs.size()]; + *Result = IDs.size(); + std::copy(IDs.begin(), IDs.end(), Result + 1); + return Result; +} + void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D); @@ -1984,7 +1975,12 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { // the specializations. SmallVector SpecIDs; ReadDeclIDList(SpecIDs); - ASTDeclReader::AddLazySpecializations(D, SpecIDs); + + if (!SpecIDs.empty()) { + auto *CommonPtr = D->getCommonPtr(); + CommonPtr->LazySpecializations = newDeclIDList( + Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs); + } } if (D->getTemplatedDecl()->TemplateOrInstantiation) { @@ -2011,7 +2007,12 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) { // the specializations. SmallVector SpecIDs; ReadDeclIDList(SpecIDs); - ASTDeclReader::AddLazySpecializations(D, SpecIDs); + + if (!SpecIDs.empty()) { + auto *CommonPtr = D->getCommonPtr(); + CommonPtr->LazySpecializations = newDeclIDList( + Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs); + } } } @@ -2117,7 +2118,12 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // This FunctionTemplateDecl owns a CommonPtr; read it. SmallVector SpecIDs; ReadDeclIDList(SpecIDs); - ASTDeclReader::AddLazySpecializations(D, SpecIDs); + + if (!SpecIDs.empty()) { + auto *CommonPtr = D->getCommonPtr(); + CommonPtr->LazySpecializations = newDeclIDList( + Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs); + } } } @@ -3661,9 +3667,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { Decl *D = Record.D; ProcessingUpdatesRAIIObj ProcessingUpdates(*this); DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); - - llvm::SmallVector PendingLazySpecializationIDs; - if (UpdI != DeclUpdateOffsets.end()) { auto UpdateOffsets = std::move(UpdI->second); DeclUpdateOffsets.erase(UpdI); @@ -3688,7 +3691,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID, SourceLocation()); - Reader.UpdateDecl(D, PendingLazySpecializationIDs); + Reader.UpdateDecl(D); // We might have made this declaration interesting. If so, remember that // we need to hand it off to the consumer. @@ -3700,17 +3703,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { } } } - // Add the lazy specializations to the template. - assert((PendingLazySpecializationIDs.empty() || isa(D) || - isa(D) || isa(D)) && - "Must not have pending specializations"); - if (auto *CTD = dyn_cast(D)) - ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs); - else if (auto *FTD = dyn_cast(D)) - ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs); - else if (auto *VTD = dyn_cast(D)) - ASTDeclReader::AddLazySpecializations(VTD, PendingLazySpecializationIDs); - PendingLazySpecializationIDs.clear(); // Load the pending visible updates for this decl context, if it has any. auto I = PendingVisibleUpdates.find(ID); @@ -3907,8 +3899,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) { } } -void ASTDeclReader::UpdateDecl(Decl *D, - llvm::SmallVectorImpl &PendingLazySpecializationIDs) { +void ASTDeclReader::UpdateDecl(Decl *D) { while (Record.getIdx() < Record.size()) { switch ((DeclUpdateKind)Record.readInt()) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: { @@ -3924,8 +3915,8 @@ void ASTDeclReader::UpdateDecl(Decl *D, } case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: - // It will be added to the template's lazy specialization set. - PendingLazySpecializationIDs.push_back(ReadDeclID()); + // It will be added to the template's specializations set when loaded. + (void)Record.readDecl(); break; case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index ee761689f479..1858bfd89637 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -957,6 +957,12 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { return RuntimeDefinition(); DynamicTypeInfo DTI = getDynamicTypeInfo(getState(), Receiver); + if (!DTI.isValid()) { + assert(isa(Receiver) && + "Unhandled untyped region class!"); + return RuntimeDefinition(); + } + QualType DynType = DTI.getType(); CanBeSubClassed = DTI.canBeASubClass(); ReceiverT = dyn_cast(DynType.getCanonicalType()); diff --git a/test/Analysis/DynamicTypePropagation.m b/test/Analysis/DynamicTypePropagation.m index 25a0ae35fd32..63904b842567 100644 --- a/test/Analysis/DynamicTypePropagation.m +++ b/test/Analysis/DynamicTypePropagation.m @@ -4,6 +4,9 @@ # error Compiler does not support Objective-C generics? #endif +typedef __typeof(sizeof(int)) size_t; +void *memset(void *, int, size_t); + #define nil 0 typedef unsigned long NSUInteger; typedef int BOOL; @@ -21,6 +24,7 @@ __attribute__((objc_root_class)) @end @interface NSArray : NSObject +- (void) init; - (BOOL)contains:(ObjectType)obj; - (ObjectType)getObjAtIndex:(NSUInteger)idx; - (ObjectType)objectAtIndexedSubscript:(NSUInteger)idx; @@ -55,3 +59,11 @@ void testArgument(NSArray *arr, id element) { // MyType! [element myFunction:0 myParam:0 ]; } + +// Do not try this at home! The analyzer shouldn't crash though when it +// tries to figure out the dynamic type behind the alloca's return value. +void testAlloca(size_t NSArrayClassSizeWeKnowSomehow) { + NSArray *arr = __builtin_alloca(NSArrayClassSizeWeKnowSomehow); + memset(arr, 0, NSArrayClassSizeWeKnowSomehow); + [arr init]; // no-crash +} diff --git a/test/Analysis/analyzer_test.py b/test/Analysis/analyzer_test.py index 58df11a4ba47..0aa2dbc1bb09 100644 --- a/test/Analysis/analyzer_test.py +++ b/test/Analysis/analyzer_test.py @@ -5,24 +5,39 @@ import lit.TestRunner class AnalyzerTest(lit.formats.ShTest): def execute(self, test, litConfig): - result = self.executeWithAnalyzeSubstitution( - test, litConfig, '-analyzer-constraints=range') + results = [] - if result.code == lit.Test.FAIL: - return result + # Parse any test requirements ('REQUIRES: ') + saved_test = test + lit.TestRunner.parseIntegratedTestScript(test) + + if 'z3' not in test.requires: + results.append(self.executeWithAnalyzeSubstitution( + saved_test, litConfig, '-analyzer-constraints=range')) + + if results[-1].code == lit.Test.FAIL: + return results[-1] # If z3 backend available, add an additional run line for it if test.config.clang_staticanalyzer_z3 == '1': - result = self.executeWithAnalyzeSubstitution( - test, litConfig, '-analyzer-constraints=z3 -DANALYZER_CM_Z3') + results.append(self.executeWithAnalyzeSubstitution( + saved_test, litConfig, '-analyzer-constraints=z3 -DANALYZER_CM_Z3')) - return result + # Combine all result outputs into the last element + for x in results: + if x != results[-1]: + results[-1].output = x.output + results[-1].output + + if results: + return results[-1] + return lit.Test.Result(lit.Test.UNSUPPORTED, + "Test requires the following unavailable features: z3") def executeWithAnalyzeSubstitution(self, test, litConfig, substitution): saved_substitutions = list(test.config.substitutions) test.config.substitutions.append(('%analyze', substitution)) result = lit.TestRunner.executeShTest(test, litConfig, - self.execute_external) + self.execute_external) test.config.substitutions = saved_substitutions return result diff --git a/test/CodeCompletion/member-access.cpp b/test/CodeCompletion/member-access.cpp index 53af121951bb..a0dc7b485679 100644 --- a/test/CodeCompletion/member-access.cpp +++ b/test/CodeCompletion/member-access.cpp @@ -145,4 +145,22 @@ public: // CHECK-CC6: o2 : [#BaseTemplate#]o2 // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:142:11 %s -o - | FileCheck -check-prefix=CHECK-CC6 %s } + + static void staticFn(T &obj); + + struct Nested { }; }; + +template +void dependentColonColonCompletion() { + Template::staticFn(); +// CHECK-CC7: function : [#void#]function() +// CHECK-CC7: Nested : Nested +// CHECK-CC7: o1 : [#BaseTemplate#]o1 +// CHECK-CC7: o2 : [#BaseTemplate#]o2 +// CHECK-CC7: staticFn : [#void#]staticFn(<#T &obj#>) +// CHECK-CC7: Template : Template +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:156:16 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s + typename Template::Nested m; +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:164:25 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s +} diff --git a/test/CodeGen/Inputs/thinlto-multi-module.ll b/test/CodeGen/Inputs/thinlto-multi-module.ll new file mode 100644 index 000000000000..e8dc16a8f572 --- /dev/null +++ b/test/CodeGen/Inputs/thinlto-multi-module.ll @@ -0,0 +1,9 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @f2() { + ret void +} + +!0 = !{i32 1, !"ThinLTO", i32 0} +!llvm.module.flags = !{ !0 } diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c index 9e5fa9f90651..34833a246920 100644 --- a/test/CodeGen/attributes.c +++ b/test/CodeGen/attributes.c @@ -56,6 +56,13 @@ void t4() {} void t7() __attribute__((noreturn, nothrow)); void t7() { while (1) {} } +// CHECK: define void @t72() [[COLDDEF:#[0-9]+]] { +void t71(void) __attribute__((cold)); +void t72() __attribute__((cold)); +void t72() { t71(); } +// CHECK: call void @t71() [[COLDSITE:#[0-9]+]] +// CHECK: declare void @t71() [[COLDDECL:#[0-9]+]] + // CHECK: define void @t10() [[NUW]] section "SECT" { void t10(void) __attribute__((section("SECT"))); void t10(void) {} @@ -92,3 +99,6 @@ void __attribute__((section(".bar"))) t22(void) {} // CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} } // CHECK: attributes [[NR]] = { noinline noreturn nounwind{{.*}} } +// CHECK: attributes [[COLDDEF]] = { cold {{.*}}} +// CHECK: attributes [[COLDDECL]] = { cold {{.*}}} +// CHECK: attributes [[COLDSITE]] = { cold {{.*}}} diff --git a/test/CodeGen/avx-builtins.c b/test/CodeGen/avx-builtins.c index 90f428efb339..31a08440d061 100644 --- a/test/CodeGen/avx-builtins.c +++ b/test/CodeGen/avx-builtins.c @@ -1427,3 +1427,51 @@ float test_mm256_cvtss_f32(__m256 __a) // CHECK: extractelement <8 x float> %{{.*}}, i32 0 return _mm256_cvtss_f32(__a); } + +__m256 test_mm256_cmp_ps_true(__m256 a, __m256 b) { + // CHECK-LABEL: @test_mm256_cmp_ps_true + // CHECK: store <8 x float> zeroinitializer, <8 x float>* %tmp, align 32 + return _mm256_cmp_ps(a, b, _CMP_FALSE_OQ); +} + +__m256 test_mm256_cmp_pd_false(__m256 a, __m256 b) { + // CHECK-LABEL: @test_mm256_cmp_pd_false + // CHECK: store <4 x double> zeroinitializer, <4 x double>* %tmp, align 32 + return _mm256_cmp_pd(a, b, _CMP_FALSE_OQ); +} + +__m256 test_mm256_cmp_ps_strue(__m256 a, __m256 b) { + // CHECK-LABEL: @test_mm256_cmp_ps_strue + // CHECK: store <8 x float> zeroinitializer, <8 x float>* %tmp, align 32 + return _mm256_cmp_ps(a, b, _CMP_FALSE_OS); +} + +__m256 test_mm256_cmp_pd_sfalse(__m256 a, __m256 b) { + // CHECK-LABEL: @test_mm256_cmp_pd_sfalse + // CHECK: store <4 x double> zeroinitializer, <4 x double>* %tmp, align 32 + return _mm256_cmp_pd(a, b, _CMP_FALSE_OS); +} diff --git a/test/CodeGen/builtins-ppc-error.c b/test/CodeGen/builtins-ppc-error.c index c3d6e639d828..29eebf286100 100644 --- a/test/CodeGen/builtins-ppc-error.c +++ b/test/CodeGen/builtins-ppc-error.c @@ -11,6 +11,8 @@ #include extern vector signed int vsi; +extern vector signed int vui; +extern vector float vf; extern vector unsigned char vuc; void testInsertWord(void) { @@ -34,3 +36,34 @@ void testXXSLDWI(int index) { vec_xxsldwi(1, 2, 3); //expected-error {{first two arguments to '__builtin_vsx_xxsldwi' must be vectors}} vec_xxsldwi(vsi, vuc, 2); //expected-error {{first two arguments to '__builtin_vsx_xxsldwi' must have the same type}} } + +void testCTF(int index) { + vec_ctf(vsi, index); //expected-error {{argument to '__builtin_altivec_vcfsx' must be a constant integer}} + vec_ctf(vui, index); //expected-error {{argument to '__builtin_altivec_vcfsx' must be a constant integer}} +} + +void testVCFSX(int index) { + vec_vcfsx(vsi, index); //expected-error {{argument to '__builtin_altivec_vcfsx' must be a constant integer}} +} + +void testVCFUX(int index) { + vec_vcfux(vui, index); //expected-error {{argument to '__builtin_altivec_vcfux' must be a constant integer}} +} + +void testCTS(int index) { + vec_cts(vf, index); //expected-error {{argument to '__builtin_altivec_vctsxs' must be a constant integer}} + +} + +void testVCTSXS(int index) { + vec_vctsxs(vf, index); //expected-error {{argument to '__builtin_altivec_vctsxs' must be a constant integer}} +} + +void testCTU(int index) { + vec_ctu(vf, index); //expected-error {{argument to '__builtin_altivec_vctuxs' must be a constant integer}} + +} + +void testVCTUXS(int index) { + vec_vctuxs(vf, index); //expected-error {{argument to '__builtin_altivec_vctuxs' must be a constant integer}} +} diff --git a/test/CodeGen/dependent-lib.c b/test/CodeGen/dependent-lib.c index 9cf49c88d77b..7178a29692a1 100644 --- a/test/CodeGen/dependent-lib.c +++ b/test/CodeGen/dependent-lib.c @@ -3,14 +3,10 @@ // RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple x86_64-pc-win32 -emit-llvm -o - | FileCheck %s // 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]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]} -// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]]} +// CHECK: !llvm.linker.options = !{![[msvcrt:[0-9]+]]} // CHECK: ![[msvcrt]] = !{!"/DEFAULTLIB:msvcrt.lib"} -// LINUX: !llvm.module.flags = !{{{.*}}} -// LINUX: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]} -// LINUX: ![[link_opts]] = !{![[msvcrt:[0-9]+]]} +// LINUX: !llvm.linker.options = !{![[msvcrt:[0-9]+]]} // LINUX: ![[msvcrt]] = !{!"-lmsvcrt"} int f(); diff --git a/test/CodeGen/linker-option.c b/test/CodeGen/linker-option.c index b1b2ec461c89..13bd981179b5 100644 --- a/test/CodeGen/linker-option.c +++ b/test/CodeGen/linker-option.c @@ -1,8 +1,6 @@ // RUN: %clang_cc1 %s --linker-option=/include:foo -triple i686-pc-win32 -emit-llvm -o - | FileCheck %s -// CHECK: !llvm.module.flags = !{{{.*}}} -// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]} -// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]]} +// CHECK: !llvm.linker.options = !{![[msvcrt:[0-9]+]]} // CHECK: ![[msvcrt]] = !{!"/include:foo"} int f(); diff --git a/test/CodeGen/mips-debug-info-bitfield.c b/test/CodeGen/mips-debug-info-bitfield.c new file mode 100644 index 000000000000..a0e2ed9cde86 --- /dev/null +++ b/test/CodeGen/mips-debug-info-bitfield.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -x c -debug-info-kind=limited -triple mips-none-linux-gnu -emit-llvm -o - %s | FileCheck %s + +struct fields +{ + unsigned a : 4; + unsigned b : 4; +} flags; + +// CHECK: !DIDerivedType(tag: DW_TAG_member, +// CHECK-SAME: {{.*}}name: "a" +// CHECK-NOT: {{.*}}offset: +// CHECK-SAME: {{.*}}flags: DIFlagBitField + +// CHECK: !DIDerivedType(tag: DW_TAG_member, +// CHECK-SAME: {{.*}}name: "b" +// CHECK-SAME: {{.*}}offset: 4 +// CHECK-SAME: {{.*}}flags: DIFlagBitField diff --git a/test/CodeGen/pragma-comment.c b/test/CodeGen/pragma-comment.c index 71a7dfc0b018..e20efacdcb22 100644 --- a/test/CodeGen/pragma-comment.c +++ b/test/CodeGen/pragma-comment.c @@ -14,9 +14,7 @@ #pragma comment(linker," /bar=" BAR) #pragma comment(linker," /foo=\"foo bar\"") -// CHECK: !llvm.module.flags = !{{{.*}}} -// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]} -// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]], ![[kernel32:[0-9]+]], ![[USER32:[0-9]+]], ![[space:[0-9]+]], ![[bar:[0-9]+]], ![[foo:[0-9]+]]} +// CHECK: !llvm.linker.options = !{![[msvcrt:[0-9]+]], ![[kernel32:[0-9]+]], ![[USER32:[0-9]+]], ![[space:[0-9]+]], ![[bar:[0-9]+]], ![[foo:[0-9]+]]} // CHECK: ![[msvcrt]] = !{!"/DEFAULTLIB:msvcrt.lib"} // CHECK: ![[kernel32]] = !{!"/DEFAULTLIB:kernel32.lib"} // CHECK: ![[USER32]] = !{!"/DEFAULTLIB:USER32.LIB"} diff --git a/test/CodeGen/pragma-detect_mismatch.c b/test/CodeGen/pragma-detect_mismatch.c index 08259fc6be71..066183d31264 100644 --- a/test/CodeGen/pragma-detect_mismatch.c +++ b/test/CodeGen/pragma-detect_mismatch.c @@ -6,8 +6,6 @@ #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: !llvm.linker.options = !{![[test:[0-9]+]], ![[test2:[0-9]+]]} // CHECK: ![[test]] = !{!"/FAILIFMISMATCH:\22test=1\22"} // CHECK: ![[test2]] = !{!"/FAILIFMISMATCH:\22test2=2\22"} diff --git a/test/CodeGen/thinlto-backend-option.ll b/test/CodeGen/thinlto-backend-option.ll index 4c7c0ea3efcd..4fcdd079df84 100644 --- a/test/CodeGen/thinlto-backend-option.ll +++ b/test/CodeGen/thinlto-backend-option.ll @@ -8,6 +8,8 @@ ; RUN: %clang -flto=thin -c -o %t.o %s ; RUN: llvm-lto -thinlto -o %t %t.o -; RUN: not %clang_cc1 -x ir %t.o -fthinlto-index=%t.thinlto.bc -backend-option -nonexistent -emit-obj -o /dev/null 2>&1 | FileCheck %s +; RUN: not %clang_cc1 -x ir %t.o -fthinlto-index=%t.thinlto.bc -backend-option -nonexistent -emit-obj -o /dev/null 2>&1 | FileCheck %s -check-prefix=UNKNOWN +; UNKNOWN: clang: Unknown command line argument '-nonexistent' -; CHECK: clang: Unknown command line argument '-nonexistent' +; RUN: not %clang_cc1 -flto=thinfoo 2>&1 | FileCheck %s -check-prefix=INVALID +; INVALID: error: invalid value 'thinfoo' in '-flto=thinfoo' diff --git a/test/CodeGen/thinlto-multi-module.ll b/test/CodeGen/thinlto-multi-module.ll index 21d28cf44da2..385d98c74d94 100644 --- a/test/CodeGen/thinlto-multi-module.ll +++ b/test/CodeGen/thinlto-multi-module.ll @@ -3,8 +3,8 @@ ; RUN: opt -module-summary -o %t1.o %s ; RUN: llvm-lto -thinlto -o %t %t1.o -; RUN: opt -o %t2.o %S/Inputs/thinlto_backend.ll -; RUN: llvm-cat -b -o %t1cat.o %t1.o %t2.o +; RUN: opt -module-summary -o %t2.o %S/Inputs/thinlto-multi-module.ll +; RUN: llvm-cat -b -o %t1cat.o %t2.o %t1.o ; RUN: cp %t1cat.o %t1.o ; RUN: %clang -target x86_64-unknown-linux-gnu -O2 -o %t3.o -x ir %t1.o -c -fthinlto-index=%t.thinlto.bc ; RUN: llvm-nm %t3.o | FileCheck --check-prefix=CHECK-OBJ %s diff --git a/test/CodeGen/ubsan-pointer-overflow.m b/test/CodeGen/ubsan-pointer-overflow.m index 56df95baff55..da622355fdb4 100644 --- a/test/CodeGen/ubsan-pointer-overflow.m +++ b/test/CodeGen/ubsan-pointer-overflow.m @@ -5,23 +5,21 @@ void unary_arith(char *p) { // CHECK: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 1, !nosanitize // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize - // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize - // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 true, i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize - // CHECK-NEXT: [[VALID:%.*]] = and i1 true, [[DIFFVALID]], !nosanitize - // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize + // CHECK-NEXT: br i1 [[POSVALID]]{{.*}}, !nosanitize // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize ++p; // CHECK: ptrtoint i8* {{.*}} to i64, !nosanitize // CHECK-NEXT: add i64 {{.*}}, -1, !nosanitize // CHECK: select i1 false{{.*}}, !nosanitize - // CHECK-NEXT: and i1 true{{.*}}, !nosanitize // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} --p; + // CHECK-NOT: select // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} p++; + // CHECK: select // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} p--; } @@ -30,22 +28,43 @@ void unary_arith(char *p) { void binary_arith(char *p, int i) { // CHECK: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %{{.*}}), !nosanitize // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize - // CHECK-NEXT: [[OFFSETOFLOW:%.*]] = or i1 false, [[SMULOFLOW]], !nosanitize // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize // CHECK-NEXT: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize + // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize - // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize // CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0, !nosanitize - // CHECK-DAG: [[OFFSETVALID:%.*]] = xor i1 [[OFFSETOFLOW]], true, !nosanitize - // CHECK-DAG: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize - // CHECK: [[VALID:%.*]] = and i1 [[OFFSETVALID]], [[DIFFVALID]], !nosanitize + // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize + // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize + // CHECK: [[VALID:%.*]] = and i1 [[DIFFVALID]], [[OFFSETVALID]], !nosanitize // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize p + i; // CHECK: [[OFFSET:%.*]] = sub i64 0, {{.*}} // CHECK-NEXT: getelementptr inbounds {{.*}} [[OFFSET]] + // CHECK: select + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} + p - i; +} + +// CHECK-LABEL: define void @binary_arith_unsigned +void binary_arith_unsigned(char *p, unsigned i) { + // CHECK: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %{{.*}}), !nosanitize + // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize + // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize + // CHECK-NEXT: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize + // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize + // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize + // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize + // CHECK: [[VALID:%.*]] = and i1 [[POSVALID]], [[OFFSETVALID]], !nosanitize + // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize + p + i; + + // CHECK: [[OFFSET:%.*]] = sub i64 0, {{.*}} + // CHECK-NEXT: getelementptr inbounds {{.*}} [[OFFSET]] + // CHECK: select // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} p - i; } @@ -55,16 +74,15 @@ void fixed_len_array(int k) { // CHECK: getelementptr inbounds [10 x [10 x i32]], [10 x [10 x i32]]* [[ARR:%.*]], i64 0, i64 [[IDXPROM:%.*]] // CHECK-NEXT: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 40, i64 [[IDXPROM]]), !nosanitize // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize - // CHECK-NEXT: [[OFFSETOFLOW:%.*]] = or i1 false, [[SMULOFLOW]], !nosanitize // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize // CHECK-NEXT: [[BASE:%.*]] = ptrtoint [10 x [10 x i32]]* [[ARR]] to i64, !nosanitize // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize + // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize - // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize // CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0, !nosanitize - // CHECK-DAG: [[OFFSETVALID:%.*]] = xor i1 [[OFFSETOFLOW]], true, !nosanitize - // CHECK-DAG: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize - // CHECK: [[VALID:%.*]] = and i1 [[OFFSETVALID]], [[DIFFVALID]], !nosanitize + // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize + // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize + // CHECK: [[VALID:%.*]] = and i1 [[DIFFVALID]], [[OFFSETVALID]], !nosanitize // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize @@ -101,6 +119,24 @@ void pointer_array(int **arr, int k) { arr[k][k]; } +// CHECK-LABEL: define void @pointer_array_unsigned_indices +void pointer_array_unsigned_indices(int **arr, unsigned k) { + // CHECK-NOT: select + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} + // CHECK-NOT: select + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} + arr[k][k]; +} + +// CHECK-LABEL: define void @pointer_array_mixed_indices +void pointer_array_mixed_indices(int **arr, int i, unsigned j) { + // CHECK: select + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} + // CHECK-NOT: select + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} + arr[i][j]; +} + struct S1 { int pad1; union { @@ -118,6 +154,7 @@ void struct_index(struct S1 *p) { // CHECK: getelementptr inbounds %struct.S1, %struct.S1* [[P:%.*]], i64 10 // CHECK-NEXT: [[BASE:%.*]] = ptrtoint %struct.S1* [[P]] to i64, !nosanitize // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 240, !nosanitize + // CHECK: select // CHECK: @__ubsan_handle_pointer_overflow{{.*}} i64 [[BASE]], i64 [[COMPGEP]]) {{.*}}, !nosanitize // CHECK-NOT: @__ubsan_handle_pointer_overflow @@ -130,10 +167,12 @@ typedef void (*funcptr_t)(void); // CHECK-LABEL: define void @function_pointer_arith void function_pointer_arith(funcptr_t *p, int k) { // CHECK: add i64 {{.*}}, 8, !nosanitize + // CHECK-NOT: select // CHECK: @__ubsan_handle_pointer_overflow{{.*}} ++p; // CHECK: @llvm.smul.with.overflow.i64(i64 8, i64 {{.*}}), !nosanitize + // CHECK: select // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} p + k; } @@ -145,11 +184,13 @@ void variable_len_array_arith(int n, int k) { // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[INC:%.*]] // CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 [[INC]]), !nosanitize + // CHECK-NOT: select // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} ++p; // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM:%.*]] // CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM]]), !nosanitize + // CHECK: select // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} p + k; } @@ -157,6 +198,7 @@ void variable_len_array_arith(int n, int k) { // CHECK-LABEL: define void @objc_id void objc_id(id *p) { // CHECK: add i64 {{.*}}, 8, !nosanitize + // CHECK-NOT: select // CHECK: @__ubsan_handle_pointer_overflow{{.*}} p++; } diff --git a/test/CodeGen/ubsan-volatile.c b/test/CodeGen/ubsan-volatile.c new file mode 100644 index 000000000000..ce54aada81fd --- /dev/null +++ b/test/CodeGen/ubsan-volatile.c @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=null,alignment,object-size,vptr -S -emit-llvm %s -o - | FileCheck %s + +// CHECK: @volatile_null_deref +void volatile_null_deref(volatile int *p) { + // CHECK-NOT: call{{.*}}ubsan + *p; +} diff --git a/test/CodeGenCXX/ms-thread_local.cpp b/test/CodeGenCXX/ms-thread_local.cpp index 5183ab5c32e1..dc7958d6eacf 100644 --- a/test/CodeGenCXX/ms-thread_local.cpp +++ b/test/CodeGenCXX/ms-thread_local.cpp @@ -27,7 +27,5 @@ A f() { return c; } -// CHECK: !llvm.module.flags = !{{{.*}}} -// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]} -// CHECK: ![[link_opts]] = !{![[dyn_tls_init:[0-9]+]]} +// CHECK: !llvm.linker.options = !{![[dyn_tls_init:[0-9]+]]} // CHECK: ![[dyn_tls_init]] = !{!"/include:___dyn_tls_init@12"} diff --git a/test/CodeGenCoroutines/coro-await.cpp b/test/CodeGenCoroutines/coro-await.cpp index 1e2deaa8f59a..fc6559f1e0ad 100644 --- a/test/CodeGenCoroutines/coro-await.cpp +++ b/test/CodeGenCoroutines/coro-await.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 \ +// RUN: -emit-llvm %s -o - -disable-llvm-passes -Wno-coroutine -Wno-unused | FileCheck %s namespace std { namespace experimental { @@ -278,3 +279,50 @@ void AwaitLValue() { suspend_always lval; co_await lval; } + +struct RefTag { }; + +struct AwaitResumeReturnsLValue { + bool await_ready(); + void await_suspend(std::experimental::coroutine_handle<>); + RefTag& await_resume(); +}; + + +template<> +struct std::experimental::coroutine_traits { + struct promise_type { + void get_return_object(); + init_susp initial_suspend(); + final_susp final_suspend(); + void return_void(); + AwaitResumeReturnsLValue yield_value(int); + }; +}; + +// Verifies that we don't crash when returning an lvalue from an await_resume() +// expression. +// CHECK-LABEL: define void @_Z18AwaitReturnsLValued(double) +void AwaitReturnsLValue(double) { + AwaitResumeReturnsLValue a; + // CHECK: %[[AVAR:.+]] = alloca %struct.AwaitResumeReturnsLValue, + // CHECK: %[[XVAR:.+]] = alloca %struct.RefTag*, + + // CHECK: %[[YVAR:.+]] = alloca %struct.RefTag*, + // CHECK-NEXT: %[[TMP1:.+]] = alloca %struct.AwaitResumeReturnsLValue, + + // CHECK: %[[ZVAR:.+]] = alloca %struct.RefTag*, + // CHECK-NEXT: %[[TMP2:.+]] = alloca %struct.AwaitResumeReturnsLValue, + + // CHECK: %[[RES1:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[AVAR]]) + // CHECK-NEXT: store %struct.RefTag* %[[RES1]], %struct.RefTag** %[[XVAR]], + RefTag& x = co_await a; + + // CHECK: %[[RES2:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[TMP1]]) + // CHECK-NEXT: store %struct.RefTag* %[[RES2]], %struct.RefTag** %[[YVAR]], + + RefTag& y = co_await AwaitResumeReturnsLValue{}; + // CHECK: %[[RES3:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[TMP2]]) + // CHECK-NEXT: store %struct.RefTag* %[[RES3]], %struct.RefTag** %[[ZVAR]], + RefTag& z = co_yield 42; +} diff --git a/test/CodeGenObjC/availability-cf-link-guard.m b/test/CodeGenObjC/availability-cf-link-guard.m index 918d13ffd9f4..6bd426476bba 100644 --- a/test/CodeGenObjC/availability-cf-link-guard.m +++ b/test/CodeGenObjC/availability-cf-link-guard.m @@ -37,9 +37,8 @@ void use_at_available() { // CHECK_NO_GUARD-NOT: __clang_at_available_requires_core_foundation_framework // CHECK_NO_GUARD-NOT: CFBundleGetVersionNumber -// CHECK_LINK_OPT: !"Linker Options", ![[OPTS:[0-9]+]] -// CHECK_LINK_OPT: ![[OPTS]] = !{![[FRAMEWORK:[0-9]+]] +// CHECK_LINK_OPT: !llvm.linker.options = !{![[FRAMEWORK:[0-9]+]] // CHECK_LINK_OPT: ![[FRAMEWORK]] = !{!"-framework", !"CoreFoundation"} -// CHECK_NO_GUARD-NOT: "Linker Options" +// CHECK_NO_GUARD-NOT: !llvm.linker.options // CHECK_NO_GUARD-NOT: CoreFoundation diff --git a/test/Coverage/ast-printing.c b/test/Coverage/ast-printing.c index eb22f92e66d7..dfda6c676f6f 100644 --- a/test/Coverage/ast-printing.c +++ b/test/Coverage/ast-printing.c @@ -3,6 +3,7 @@ // RUN: %clang_cc1 -ast-print %t.1.c -o %t.2.c // RUN: diff %t.1.c %t.2.c // RUN: %clang_cc1 -ast-dump %s +// RUN: %clang_cc1 -ast-dump-all %s // RUN: %clang_cc1 -print-decl-contexts %s #include "c-language-features.inc" diff --git a/test/Coverage/ast-printing.cpp b/test/Coverage/ast-printing.cpp index e03c51735335..bcd78be7d05b 100644 --- a/test/Coverage/ast-printing.cpp +++ b/test/Coverage/ast-printing.cpp @@ -3,6 +3,7 @@ // RUN: %clang_cc1 -std=c++14 -ast-print %t.1.cpp -o %t.2.cpp // RUN: diff %t.1.cpp %t.2.cpp // RUN: %clang_cc1 -std=c++14 -ast-dump %s +// RUN: %clang_cc1 -std=c++14 -ast-dump-all %s // RUN: %clang_cc1 -std=c++14 -print-decl-contexts %s // RUN: %clang_cc1 -std=c++14 -fdump-record-layouts %s diff --git a/test/Driver/m_and_mm.c b/test/Driver/m_and_mm.c index 18cf7abfa629..6e40c82cb16c 100644 --- a/test/Driver/m_and_mm.c +++ b/test/Driver/m_and_mm.c @@ -1,3 +1,15 @@ // RUN: %clang -### \ // RUN: -M -MM %s 2> %t // RUN: not grep '"-sys-header-deps"' %t + +// RUN: %clang -M -MM %s 2> %t +// RUN: not grep "warning" %t + +// RUN: %clang -MMD -MD %s 2> %t || true +// RUN: grep "warning" %t + +#warning "This warning shouldn't show up with -M and -MM" +int main (void) +{ + return 0; +} diff --git a/test/Index/Core/index-source.cpp b/test/Index/Core/index-source.cpp index 8b049314ffbe..10f2d8f77747 100644 --- a/test/Index/Core/index-source.cpp +++ b/test/Index/Core/index-source.cpp @@ -1,4 +1,4 @@ -// RUN: c-index-test core -print-source-symbols -- %s -std=c++14 -target x86_64-apple-macosx10.7 | FileCheck %s +// RUN: c-index-test core -print-source-symbols -- %s -std=c++1z -target x86_64-apple-macosx10.7 | FileCheck %s // CHECK: [[@LINE+1]]:7 | class/C++ | Cls | [[Cls_USR:.*]] | | Def | rel: 0 class Cls { public: @@ -433,3 +433,45 @@ template T varDecl = T(); } // end namespace ensureDefaultTemplateParamsAreRecordedOnce + +struct StaticAssertRef { + static constexpr bool constVar = true; +}; + +static_assert(StaticAssertRef::constVar, "index static asserts"); +// CHECK: [[@LINE-1]]:32 | static-property/C++ | constVar | c:@S@StaticAssertRef@constVar | __ZN15StaticAssertRef8constVarE | Ref | rel: 0 +// CHECK: [[@LINE-2]]:15 | struct/C++ | StaticAssertRef | c:@S@StaticAssertRef | | Ref | rel: 0 + +void staticAssertInFn() { + static_assert(StaticAssertRef::constVar, "index static asserts"); +// CHECK: [[@LINE-1]]:34 | static-property/C++ | constVar | c:@S@StaticAssertRef@constVar | __ZN15StaticAssertRef8constVarE | Ref,RelCont | rel: 1 +// CHECK-NEXT: RelCont | staticAssertInFn | c:@F@staticAssertInFn# +// CHECK: [[@LINE-3]]:17 | struct/C++ | StaticAssertRef | c:@S@StaticAssertRef | | Ref,RelCont | rel: 1 +// CHECK-NEXT: RelCont | staticAssertInFn | c:@F@staticAssertInFn# +} + +namespace cpp17structuredBinding { + +struct Cpp17StructuredBinding { + int x, y; + + Cpp17StructuredBinding(int x, int y): x(x), y(y) { } +}; + +auto [structuredBinding1, structuredBinding2] = Cpp17StructuredBinding(Record::C, 0); +// CHECK: [[@LINE-1]]:7 | variable/C++ | structuredBinding1 | c:@N@cpp17structuredBinding@structuredBinding1 | | Decl,RelChild | rel: 1 +// CHECK-NEXT: RelChild | cpp17structuredBinding | c:@N@cpp17structuredBinding +// CHECK: [[@LINE-3]]:27 | variable/C++ | structuredBinding2 | c:@N@cpp17structuredBinding@structuredBinding2 | | Decl,RelChild | rel: 1 +// CHECK-NEXT: RelChild | cpp17structuredBinding | c:@N@cpp17structuredBinding + +void localStructuredBindingAndRef() { + int ref = structuredBinding1; +// CHECK: [[@LINE-1]]:13 | variable/C++ | structuredBinding1 | c:@N@cpp17structuredBinding@structuredBinding1 | | Ref,Read,RelCont | rel: 1 +// CHECK-NEXT: RelCont | localStructuredBindingAndRef | c:@N@cpp17structuredBinding@F@localStructuredBindingAndRef# + auto [localBinding1, localBinding2] = Cpp17StructuredBinding(ref, structuredBinding2); +// CHECK: [[@LINE-1]]:69 | variable/C++ | structuredBinding2 | c:@N@cpp17structuredBinding@structuredBinding2 | | Ref,Read,RelCont | rel: 1 +// CHECK-NEXT: RelCont | localStructuredBindingAndRef | c:@N@cpp17structuredBinding@F@localStructuredBindingAndRef# +// CHECK-NOT: localBinding +} + +} diff --git a/test/Index/availability.c b/test/Index/availability.c index b9d2c6f449c1..206b8a2a7105 100644 --- a/test/Index/availability.c +++ b/test/Index/availability.c @@ -8,13 +8,15 @@ enum { enum { old_enum_plat -} __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7) +} __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7))); -// RUN: c-index-test -test-load-source all %s > %t -// RUN: FileCheck -check-prefix=CHECK-1 %s < %t -// RUN: FileCheck -check-prefix=CHECK-2 %s < %t -// CHECK-1: (ios, introduced=3.2, deprecated=4.1) -// CHECK-2: (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7) +void bar(void) __attribute__((availability(macosx,introduced=10.4))) __attribute__((availability(macosx,obsoleted=10.6))) __attribute__((availability(ios,introduced=3.2))) __attribute__((availability(macosx,deprecated=10.5,message="use foobar"))); -// CHECK-2: EnumConstantDecl=old_enum:6:3 (Definition) (deprecated) -// CHECK-2: EnumConstantDecl=old_enum_plat:10:3 {{.*}} (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7) +void bar2(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7))) __attribute__((availability(ios,introduced=3.2,deprecated=10.0))) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7))) __attribute__((availability(ios,introduced=3.2,deprecated=10.0))); + +// RUN: c-index-test -test-load-source all %s | FileCheck %s +// CHECK: FunctionDecl=foo:3:6{{.*}}(ios, introduced=3.2, deprecated=4.1) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7) +// CHECK: EnumConstantDecl=old_enum:6:3 (Definition) (deprecated) +// CHECK: EnumConstantDecl=old_enum_plat:10:3 {{.*}} (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7) +// CHECK: FunctionDecl=bar:13:6{{.*}}(ios, introduced=3.2) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.6, message="use foobar") +// CHECK: FunctionDecl=bar2:15:6{{.*}}(ios, introduced=3.2, deprecated=10.0) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7) diff --git a/test/Misc/pr32207.c b/test/Misc/pr32207.c new file mode 100644 index 000000000000..f738e41684c6 --- /dev/null +++ b/test/Misc/pr32207.c @@ -0,0 +1,4 @@ +// test for r305179 +// RUN: %clang_cc1 -emit-llvm -O -mllvm -print-after-all %s -o %t 2>&1 | FileCheck %s +// CHECK: *** IR Dump After Function Integration/Inlining *** +void foo() {} diff --git a/test/Modules/autolink.m b/test/Modules/autolink.m index 28b9e40678f6..6aee0e11b120 100644 --- a/test/Modules/autolink.m +++ b/test/Modules/autolink.m @@ -36,9 +36,7 @@ int use_autolink_sub3() { // NOTE: "autolink_sub" is intentionally not linked. -// CHECK: !llvm.module.flags = !{{{.*}}} -// 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: !llvm.linker.options = !{![[AUTOLINK_PCH:[0-9]+]], ![[AUTOLINK_FRAMEWORK:[0-9]+]], ![[AUTOLINK:[0-9]+]], ![[DEPENDSONMODULE:[0-9]+]], ![[MODULE:[0-9]+]], ![[NOUMBRELLA:[0-9]+]]} // CHECK: ![[AUTOLINK_PCH]] = !{!"{{(\\01|-l|/DEFAULTLIB:)}}autolink_from_pch{{(\.lib)?}}"} // CHECK: ![[AUTOLINK_FRAMEWORK]] = !{!"-framework", !"autolink_framework"} // CHECK: ![[AUTOLINK]] = !{!"{{(\\01|-l|/DEFAULTLIB:)}}autolink{{(\.lib)?}}"} @@ -47,4 +45,4 @@ int use_autolink_sub3() { // CHECK: ![[NOUMBRELLA]] = !{!"-framework", !"NoUmbrella"} // CHECK-AUTOLINK-DISABLED: !llvm.module.flags -// CHECK-AUTOLINK-DISABLED-NOT: "Linker Options" +// CHECK-AUTOLINK-DISABLED-NOT: !llvm.linker.options diff --git a/test/Modules/autolinkTBD.m b/test/Modules/autolinkTBD.m index 6107952c3b9b..d6b9e997b2f8 100644 --- a/test/Modules/autolinkTBD.m +++ b/test/Modules/autolinkTBD.m @@ -8,10 +8,8 @@ int f() { return foo(); } -// CHECK: !llvm.module.flags = !{{{.*}}} -// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[AUTOLINK_OPTIONS:[0-9]+]]} -// CHECK: ![[AUTOLINK_OPTIONS]] = !{![[AUTOLINK_FRAMEWORK:[0-9]+]]} +// CHECK: !llvm.linker.options = !{![[AUTOLINK_FRAMEWORK:[0-9]+]]} // CHECK: ![[AUTOLINK_FRAMEWORK]] = !{!"-framework", !"AutolinkTBD"} // CHECK-AUTOLINK-DISABLED: !llvm.module.flags -// CHECK-AUTOLINK-DISABLED-NOT: "Linker Options" +// CHECK-AUTOLINK-DISABLED-NOT: !llvm.linker.options diff --git a/test/Modules/module-impl-with-link.c b/test/Modules/module-impl-with-link.c index 3bd4c4abd92b..ffd388c56b90 100644 --- a/test/Modules/module-impl-with-link.c +++ b/test/Modules/module-impl-with-link.c @@ -1,7 +1,6 @@ // RUN: rm -rf %t // RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -fmodule-name=Clib %s -I %S/Inputs/module-impl-with-link -emit-llvm -o - | FileCheck %s #include "foo.h" -// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[LINK_OPTIONS:[0-9]+]]} // Make sure we don't generate linker option for module Clib since this TU is // an implementation of Clib. -// CHECK: ![[LINK_OPTIONS]] = !{} +// CHECK: !llvm.linker.options = !{} diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp index a6a0b74743aa..c94940c73eb6 100644 --- a/test/Modules/odr_hash.cpp +++ b/test/Modules/odr_hash.cpp @@ -486,7 +486,8 @@ struct S12 { }; #else S12 s12; -// TODO: This should produce an error. +// expected-error@second.h:* {{'Method::S12' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter without a default argument}} +// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter with a default argument}} #endif #if defined(FIRST) @@ -499,7 +500,8 @@ struct S13 { }; #else S13 s13; -// TODO: This should produce an error. +// expected-error@second.h:* {{'Method::S13' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter with a default argument}} +// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter with a different default argument}} #endif #if defined(FIRST) @@ -586,6 +588,57 @@ S3 s3; // expected-error@first.h:* {{'TypeDef::S3::a' from module 'FirstModule' is not present in definition of 'TypeDef::S3' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'a' does not match}} #endif + +#if defined(FIRST) +struct S4 { + typedef int a; + typedef int b; +}; +#elif defined(SECOND) +struct S4 { + typedef int b; + typedef int a; +}; +#else +S4 s4; +// expected-error@second.h:* {{'TypeDef::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found typedef name 'b'}} +// expected-note@first.h:* {{but in 'FirstModule' found typedef name 'a'}} +#endif + +#if defined(FIRST) +struct S5 { + typedef int a; + typedef int b; + int x; +}; +#elif defined(SECOND) +struct S5 { + int x; + typedef int b; + typedef int a; +}; +#else +S5 s5; +// expected-error@second.h:* {{'TypeDef::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}} +// expected-note@first.h:* {{but in 'FirstModule' found typedef}} +#endif + +#if defined(FIRST) +typedef float F; +struct S6 { + typedef int a; + typedef F b; +}; +#elif defined(SECOND) +struct S6 { + typedef int a; + typedef float b; +}; +#else +S6 s6; +// expected-error@second.h:* {{'TypeDef::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found typedef 'b' with underlying type 'float'}} +// expected-note@first.h:* {{but in 'FirstModule' found typedef 'b' with different underlying type 'TypeDef::F' (aka 'float')}} +#endif } // namespace TypeDef namespace Using { @@ -632,6 +685,57 @@ S3 s3; // expected-error@first.h:* {{'Using::S3::a' from module 'FirstModule' is not present in definition of 'Using::S3' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'a' does not match}} #endif + +#if defined(FIRST) +struct S4 { + using a = int; + using b = int; +}; +#elif defined(SECOND) +struct S4 { + using b = int; + using a = int; +}; +#else +S4 s4; +// expected-error@second.h:* {{'Using::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias name 'b'}} +// expected-note@first.h:* {{but in 'FirstModule' found type alias name 'a'}} +#endif + +#if defined(FIRST) +struct S5 { + using a = int; + using b = int; + int x; +}; +#elif defined(SECOND) +struct S5 { + int x; + using b = int; + using a = int; +}; +#else +S5 s5; +// expected-error@second.h:* {{'Using::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}} +// expected-note@first.h:* {{but in 'FirstModule' found type alias}} +#endif + +#if defined(FIRST) +typedef float F; +struct S6 { + using a = int; + using b = F; +}; +#elif defined(SECOND) +struct S6 { + using a = int; + using b = float; +}; +#else +S6 s6; +// expected-error@second.h:* {{'Using::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'b' with underlying type 'float'}} +// expected-note@first.h:* {{but in 'FirstModule' found type alias 'b' with different underlying type 'Using::F' (aka 'float')}} +#endif } // namespace Using namespace RecordType { @@ -900,6 +1004,289 @@ S2 s2; #endif } +namespace TemplateArgument { +#if defined(FIRST) +template struct U1{}; +struct S1 { + U1 x; +}; +#elif defined(SECOND) +template struct U1{}; +struct S1 { + U1<1> x; +}; +#else +S1 s1; +// expected-error@first.h:* {{'TemplateArgument::S1::x' from module 'FirstModule' is not present in definition of 'TemplateArgument::S1' in module 'SecondModule'}} +// expected-note@second.h:* {{declaration of 'x' does not match}} +#endif + +#if defined(FIRST) +template struct U2{}; +struct S2 { + using T = U2<2>; +}; +#elif defined(SECOND) +template struct U2{}; +struct S2 { + using T = U2<(2)>; +}; +#else +S2 s2; +// expected-error@second.h:* {{'TemplateArgument::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'T' with underlying type 'U2<(2)>'}} +// expected-note@first.h:* {{but in 'FirstModule' found type alias 'T' with different underlying type 'U2<2>'}} +#endif + +#if defined(FIRST) +template struct U3{}; +struct S3 { + using T = U3<2>; +}; +#elif defined(SECOND) +template struct U3{}; +struct S3 { + using T = U3<1 + 1>; +}; +#else +S3 s3; +// expected-error@second.h:* {{'TemplateArgument::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'T' with underlying type 'U3<1 + 1>'}} +// expected-note@first.h:* {{but in 'FirstModule' found type alias 'T' with different underlying type 'U3<2>'}} +#endif + +#if defined(FIRST) +template struct T4a {}; +template