aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/ClangFormatStyleOptions.rst10
-rw-r--r--docs/ReleaseNotes.rst25
-rw-r--r--docs/UndefinedBehaviorSanitizer.rst6
-rw-r--r--include/clang/Basic/AllDiagnostics.h2
-rw-r--r--include/clang/Basic/BuiltinsPPC.def8
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td34
-rw-r--r--include/clang/Format/Format.h36
-rw-r--r--include/clang/Frontend/FrontendOptions.h4
-rw-r--r--include/clang/Lex/MacroArgs.h16
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--lib/AST/ASTContext.cpp3
-rw-r--r--lib/AST/ExprClassification.cpp4
-rw-r--r--lib/AST/ExprConstant.cpp33
-rw-r--r--lib/AST/ItaniumMangle.cpp2
-rw-r--r--lib/AST/ODRHash.cpp47
-rw-r--r--lib/CodeGen/BackendUtil.cpp8
-rw-r--r--lib/CodeGen/CGBuiltin.cpp21
-rw-r--r--lib/CodeGen/CGCall.cpp2
-rw-r--r--lib/CodeGen/CGCoroutine.cpp66
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp18
-rw-r--r--lib/CodeGen/CGExpr.cpp47
-rw-r--r--lib/CodeGen/CGExprScalar.cpp51
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.cpp2
-rw-r--r--lib/CodeGen/CodeGenFunction.h4
-rw-r--r--lib/CodeGen/CodeGenModule.cpp10
-rw-r--r--lib/CodeGen/CodeGenModule.h7
-rw-r--r--lib/Driver/ToolChains/Clang.cpp3
-rw-r--r--lib/Format/Format.cpp16
-rw-r--r--lib/Format/NamespaceEndCommentsFixer.cpp64
-rw-r--r--lib/Format/UnwrappedLineFormatter.cpp80
-rw-r--r--lib/Format/UnwrappedLineParser.cpp5
-rw-r--r--lib/Format/WhitespaceManager.h4
-rw-r--r--lib/Frontend/ASTConsumers.cpp2
-rw-r--r--lib/Frontend/CompilerInvocation.cpp10
-rw-r--r--lib/Index/IndexDecl.cpp13
-rw-r--r--lib/Index/IndexSymbol.cpp4
-rw-r--r--lib/Lex/MacroArgs.cpp20
-rw-r--r--lib/Sema/SemaCodeComplete.cpp10
-rw-r--r--lib/Sema/SemaCoroutine.cpp35
-rw-r--r--lib/Sema/SemaDeclAttr.cpp14
-rw-r--r--lib/Sema/SemaExpr.cpp8
-rw-r--r--lib/Sema/SemaExprCXX.cpp9
-rw-r--r--lib/Sema/SemaLambda.cpp16
-rw-r--r--lib/Sema/SemaStmt.cpp58
-rw-r--r--lib/Serialization/ASTReader.cpp154
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp85
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp6
-rw-r--r--test/Analysis/DynamicTypePropagation.m12
-rw-r--r--test/Analysis/analyzer_test.py31
-rw-r--r--test/CodeCompletion/member-access.cpp18
-rw-r--r--test/CodeGen/Inputs/thinlto-multi-module.ll9
-rw-r--r--test/CodeGen/attributes.c10
-rw-r--r--test/CodeGen/avx-builtins.c48
-rw-r--r--test/CodeGen/builtins-ppc-error.c33
-rw-r--r--test/CodeGen/dependent-lib.c8
-rw-r--r--test/CodeGen/linker-option.c4
-rw-r--r--test/CodeGen/mips-debug-info-bitfield.c17
-rw-r--r--test/CodeGen/pragma-comment.c4
-rw-r--r--test/CodeGen/pragma-detect_mismatch.c4
-rw-r--r--test/CodeGen/thinlto-backend-option.ll6
-rw-r--r--test/CodeGen/thinlto-multi-module.ll4
-rw-r--r--test/CodeGen/ubsan-pointer-overflow.m72
-rw-r--r--test/CodeGen/ubsan-volatile.c7
-rw-r--r--test/CodeGenCXX/ms-thread_local.cpp4
-rw-r--r--test/CodeGenCoroutines/coro-await.cpp50
-rw-r--r--test/CodeGenObjC/availability-cf-link-guard.m5
-rw-r--r--test/Coverage/ast-printing.c1
-rw-r--r--test/Coverage/ast-printing.cpp1
-rw-r--r--test/Driver/m_and_mm.c12
-rw-r--r--test/Index/Core/index-source.cpp44
-rw-r--r--test/Index/availability.c18
-rw-r--r--test/Misc/pr32207.c4
-rw-r--r--test/Modules/autolink.m6
-rw-r--r--test/Modules/autolinkTBD.m6
-rw-r--r--test/Modules/module-impl-with-link.c3
-rw-r--r--test/Modules/odr_hash.cpp391
-rw-r--r--test/Sema/integer-overflow.c8
-rw-r--r--test/Sema/xray-log-args-class.cpp7
-rw-r--r--test/SemaCXX/co_await-range-for.cpp165
-rw-r--r--test/SemaCXX/cxx1z-decomposition.cpp6
-rw-r--r--test/SemaCXX/nested-name-spec.cpp7
-rw-r--r--test/SemaCXX/warn-unused-lambda-capture.cpp5
-rwxr-xr-xtools/clang-format/git-clang-format2
-rw-r--r--tools/libclang/CIndex.cpp120
-rw-r--r--unittests/AST/CommentLexer.cpp3
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h9
-rw-r--r--unittests/Basic/VirtualFileSystemTest.cpp6
-rw-r--r--unittests/Format/FormatTest.cpp261
-rw-r--r--unittests/Format/NamespaceEndCommentsFixerTest.cpp56
-rw-r--r--unittests/Lex/LexerTest.cpp73
-rw-r--r--unittests/Tooling/LookupTest.cpp6
91 files changed, 2244 insertions, 406 deletions
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 <size_t SizeOfStr, typename FieldType>
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<InitListExpr>(E)->getInit(0));
case Expr::CoawaitExprClass:
- return ClassifyInternal(Ctx, cast<CoawaitExpr>(E)->getResumeExpr());
+ case Expr::CoyieldExprClass:
+ return ClassifyInternal(Ctx, cast<CoroutineSuspendExpr>(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<const Expr*> 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<const Expr*> 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<FunctionProtoType>(FD->getType()->getAs<FunctionType>());
+ 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<BitcodeModule> 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<bool> HasSummary = BM.hasSummary();
- if (HasSummary && *HasSummary)
+ Expected<BitcodeLTOInfo> 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<NoReturnAttr>())
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
+ if (TargetDecl->hasAttr<ColdAttr>())
+ FuncAttrs.addAttribute(llvm::Attribute::Cold);
if (TargetDecl->hasAttr<NoDuplicateAttr>())
FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
if (TargetDecl->hasAttr<ConvergentAttr>())
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<UnaryOperator>(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<CallExpr>(RE) && "unexpected suspend expression type");
+ return cast<CallExpr>(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<GetParamRef> {
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<BlocksAttr>()) {
// 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<int64_t, 9> 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<std::pair<llvm::Value *, SanitizerMask>, 3> Checks;
@@ -1158,6 +1163,11 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::MaterializeTemporaryExprClass:
return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
+
+ case Expr::CoawaitExprClass:
+ return EmitCoawaitLValue(cast<CoawaitExpr>(E));
+ case Expr::CoyieldExprClass:
+ return EmitCoyieldLValue(cast<CoyieldExpr>(E));
}
}
@@ -3002,10 +3012,11 @@ static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF,
llvm::Value *ptr,
ArrayRef<llvm::Value*> 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<llvm::Value *> 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<VectorType>()->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<ObjCObjectType>()){
// 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<AtomicType>()) {
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<llvm::IntegerType>(index->getType())->getBitWidth();
auto &DL = CGF.CGM.getDataLayout();
auto PtrTy = cast<llvm::PointerType>(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<Value *> 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<llvm::Value *> 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<llvm::Metadata *> &Metadata,
+ SmallVectorImpl<llvm::MDNode *> &Metadata,
llvm::SmallPtrSet<Module *, 16> &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<llvm::Metadata *, 16> MetadataArgs;
+ SmallVector<llvm::MDNode *, 16> 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<clang::Module *, 16> EmittedModuleInitializers;
/// \brief A vector of metadata strings.
- SmallVector<llvm::Metadata *, 16> LinkerOptionsMetadata;
+ SmallVector<llvm::MDNode *, 16> 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<FormatStyle> {
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<FormatStyle> {
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<FormatStyle::BraceWrappingFlags> {
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<AnnotatedLine *> &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<AnnotatedLine *> &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<AnnotatedLine *> &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<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::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<AnnotatedLine *>::const_iterator End;
SmallVectorImpl<AnnotatedLine *>::const_iterator Next;
+ const SmallVectorImpl<AnnotatedLine *> &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<ASTConsumer> 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<ASTPrinter>(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<SymbolRelation, 4> 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<NamedDecl>(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<FunctionDecl>(S.CurContext);
+ auto *Fn = cast<FunctionDecl>(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<Stmt>(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 <typename AttrInfo>
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<DecompositionDecl>(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<TypedefNameDecl>(FirstDecl);
+ TypedefNameDecl *SecondTD = cast<TypedefNameDecl>(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<VarDecl>(FirstDecl);
+ VarDecl *SecondVD = cast<VarDecl>(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 <typename T> static
- void AddLazySpecializations(T *D,
- SmallVectorImpl<serialization::DeclID>& 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 <typename DeclT>
static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D);
static Decl *getMostRecentDeclImpl(...);
@@ -268,7 +244,7 @@ namespace clang {
void ReadFunctionDefinition(FunctionDecl *FD);
void Visit(Decl *D);
- void UpdateDecl(Decl *D, llvm::SmallVectorImpl<serialization::DeclID>&);
+ 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<DeclID> &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<serialization::DeclID, 32> 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<serialization::DeclID, 32> 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<serialization::DeclID, 32> 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<serialization::DeclID, 8> 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<ClassTemplateDecl>(D) ||
- isa<FunctionTemplateDecl>(D) || isa<VarTemplateDecl>(D)) &&
- "Must not have pending specializations");
- if (auto *CTD = dyn_cast<ClassTemplateDecl>(D))
- ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs);
- else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
- ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs);
- else if (auto *VTD = dyn_cast<VarTemplateDecl>(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<serialization::DeclID> &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<AllocaRegion>(Receiver) &&
+ "Unhandled untyped region class!");
+ return RuntimeDefinition();
+ }
+
QualType DynType = DTI.getType();
CanBeSubClassed = DTI.canBeASubClass();
ReceiverT = dyn_cast<ObjCObjectPointerType>(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<ObjectType> : NSObject
+- (void) init;
- (BOOL)contains:(ObjectType)obj;
- (ObjectType)getObjAtIndex:(NSUInteger)idx;
- (ObjectType)objectAtIndexedSubscript:(NSUInteger)idx;
@@ -55,3 +59,11 @@ void testArgument(NSArray<MyType *> *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<T>#]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<typename T>
+void dependentColonColonCompletion() {
+ Template<T>::staticFn();
+// CHECK-CC7: function : [#void#]function()
+// CHECK-CC7: Nested : Nested
+// CHECK-CC7: o1 : [#BaseTemplate<int>#]o1
+// CHECK-CC7: o2 : [#BaseTemplate<T>#]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<T>::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> <float 0xFFFFFFFFE0000000,
+ return _mm256_cmp_ps(a, b, _CMP_TRUE_UQ);
+}
+
+__m256 test_mm256_cmp_pd_true(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_pd_true
+ // CHECK: store <4 x double> <double 0xFFFFFFFFFFFFFFFF,
+ return _mm256_cmp_pd(a, b, _CMP_TRUE_UQ);
+}
+
+__m256 test_mm256_cmp_ps_false(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_ps_false
+ // 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> <float 0xFFFFFFFFE0000000,
+ return _mm256_cmp_ps(a, b, _CMP_TRUE_US);
+}
+
+__m256 test_mm256_cmp_pd_strue(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_pd_strue
+ // CHECK: store <4 x double> <double 0xFFFFFFFFFFFFFFFF,
+ return _mm256_cmp_pd(a, b, _CMP_TRUE_US);
+}
+
+__m256 test_mm256_cmp_ps_sfalse(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_ps_sfalse
+ // 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 <altivec.h>
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<void,double> {
+ 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:.*]] | <no-cgname> | Def | rel: 0
class Cls { public:
@@ -433,3 +433,45 @@ template<typename T>
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 | <no-cgname> | 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 | <no-cgname> | 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 | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | cpp17structuredBinding | c:@N@cpp17structuredBinding
+// CHECK: [[@LINE-3]]:27 | variable/C++ | structuredBinding2 | c:@N@cpp17structuredBinding@structuredBinding2 | <no-cgname> | 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 | <no-cgname> | 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 | <no-cgname> | 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 <class> struct U1{};
+struct S1 {
+ U1<int> x;
+};
+#elif defined(SECOND)
+template <int> 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 <int> struct U2{};
+struct S2 {
+ using T = U2<2>;
+};
+#elif defined(SECOND)
+template <int> 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 <int> struct U3{};
+struct S3 {
+ using T = U3<2>;
+};
+#elif defined(SECOND)
+template <int> 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<class> struct T4a {};
+template <template <class> class T> struct U4 {};
+struct S4 {
+ U4<T4a> x;
+};
+#elif defined(SECOND)
+template<class> struct T4b {};
+template <template <class> class T> struct U4 {};
+struct S4 {
+ U4<T4b> x;
+};
+#else
+S4 s4;
+// expected-error@first.h:* {{'TemplateArgument::S4::x' from module 'FirstModule' is not present in definition of 'TemplateArgument::S4' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+}
+
+namespace TemplateTypeParmType {
+#if defined(FIRST)
+template <class T1, class T2>
+struct S1 {
+ T1 x;
+};
+#elif defined(SECOND)
+template <class T1, class T2>
+struct S1 {
+ T2 x;
+};
+#else
+using TemplateTypeParmType::S1;
+// expected-error@first.h:* {{'TemplateTypeParmType::S1::x' from module 'FirstModule' is not present in definition of 'S1<T1, T2>' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+template <int ...Ts>
+struct U2 {};
+template <int T, int U>
+class S2 {
+ typedef U2<U, T> type;
+ type x;
+};
+#elif defined(SECOND)
+template <int ...Ts>
+struct U2 {};
+template <int T, int U>
+class S2 {
+ typedef U2<T, U> type;
+ type x;
+};
+#else
+using TemplateTypeParmType::S2;
+// expected-error@first.h:* {{'TemplateTypeParmType::S2::x' from module 'FirstModule' is not present in definition of 'S2<T, U>' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+// expected-error@first.h:* {{'TemplateTypeParmType::S2::type' from module 'FirstModule' is not present in definition of 'S2<T, U>' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'type' does not match}}
+#endif
+}
+
+namespace VarDecl {
+#if defined(FIRST)
+struct S1 {
+ static int x;
+ static int y;
+};
+#elif defined(SECOND)
+struct S1 {
+ static int y;
+ static int x;
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'VarDecl::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member with name 'y'}}
+// expected-note@first.h:* {{but in 'FirstModule' found data member with name 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ static int x;
+};
+#elif defined(SECOND)
+using I = int;
+struct S2 {
+ static I x;
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'VarDecl::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with type 'VarDecl::I' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' with different type 'int'}}
+#endif
+
+#if defined(FIRST)
+struct S3 {
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S3 {
+ static const int x;
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'VarDecl::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with an initializer}}
+// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' without an initializer}}
+#endif
+
+#if defined(FIRST)
+struct S4 {
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S4 {
+ static const int x = 2;
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'VarDecl::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with an initializer}}
+// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' with a different initializer}}
+#endif
+
+#if defined(FIRST)
+struct S5 {
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S5 {
+ static constexpr int x = 1;
+};
+#else
+S5 s5;
+// expected-error@second.h:* {{'VarDecl::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' is not constexpr}}
+// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' is constexpr}}
+#endif
+
+#if defined(FIRST)
+struct S6 {
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S6 {
+ static const int y = 1;
+};
+#else
+S6 s6;
+// expected-error@first.h:* {{'VarDecl::S6::x' from module 'FirstModule' is not present in definition of 'VarDecl::S6' in module 'SecondModule'}}
+// expected-note@second.h:* {{definition has no member 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S7 {
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S7 {
+ static const unsigned x = 1;
+};
+#else
+S7 s7;
+// expected-error@first.h:* {{'VarDecl::S7::x' from module 'FirstModule' is not present in definition of 'VarDecl::S7' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+struct S8 {
+public:
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S8 {
+ static const int x = 1;
+public:
+};
+#else
+S8 s8;
+// expected-error@second.h:* {{'VarDecl::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+
+#if defined(FIRST)
+struct S9 {
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S9 {
+ static int x;
+};
+#else
+S9 s9;
+// expected-error@first.h:* {{'VarDecl::S9::x' from module 'FirstModule' is not present in definition of 'VarDecl::S9' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+template <typename T>
+struct S {
+ struct R {
+ void foo(T x = 0) {}
+ };
+};
+#elif defined(SECOND)
+template <typename T>
+struct S {
+ struct R {
+ void foo(T x = 1) {}
+ };
+};
+#else
+void run() {
+ S<int>::R().foo();
+}
+// expected-error@second.h:* {{'VarDecl::S::R' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'foo' with 1st parameter with a default argument}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'foo' with 1st parameter with a different default argument}}
+#endif
+
+#if defined(FIRST)
+template <typename alpha> struct Bravo {
+ void charlie(bool delta = false) {}
+};
+typedef Bravo<char> echo;
+echo foxtrot;
+#elif defined(SECOND)
+template <typename alpha> struct Bravo {
+ void charlie(bool delta = (false)) {}
+};
+typedef Bravo<char> echo;
+echo foxtrot;
+#else
+Bravo<char> golf;
+// expected-error@second.h:* {{'VarDecl::Bravo' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'charlie' with 1st parameter with a default argument}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'charlie' with 1st parameter with a different default argument}}
+#endif
+}
+
// Interesting cases that should not cause errors. struct S should not error
// while struct T should error at the access specifier mismatch at the end.
namespace AllDecls {
diff --git a/test/Sema/integer-overflow.c b/test/Sema/integer-overflow.c
index c2b6ba209b71..62ee33e3d181 100644
--- a/test/Sema/integer-overflow.c
+++ b/test/Sema/integer-overflow.c
@@ -151,14 +151,6 @@ uint64_t check_integer_overflows(int i) {
uint64_t *b;
uint64_t b2 = b[4608 * 1024 * 1024] + 1;
-// expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}}
- f0(4608 * 1024 * 1024);
- f0(4608ul * 1024 * 1024);
-// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
- f1(4608 * 1024 * 1024, 4608 * 1024 * 1024);
-// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
- f2(4608 * 1024 * 1024, 4608 * 1024 * 1024);
-
// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
int j1 = i ? (4608 * 1024 * 1024) : (4608 * 1024 * 1024);
diff --git a/test/Sema/xray-log-args-class.cpp b/test/Sema/xray-log-args-class.cpp
new file mode 100644
index 000000000000..10da93f614fe
--- /dev/null
+++ b/test/Sema/xray-log-args-class.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c++11 -x c++
+
+class Class {
+ [[clang::xray_always_instrument, clang::xray_log_args(1)]] void Method();
+ [[clang::xray_log_args(-1)]] void Invalid(); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}}
+ [[clang::xray_log_args("invalid")]] void InvalidStringArg(); // expected-error {{'xray_log_args'}}
+};
diff --git a/test/SemaCXX/co_await-range-for.cpp b/test/SemaCXX/co_await-range-for.cpp
new file mode 100644
index 000000000000..4d999ea7db5e
--- /dev/null
+++ b/test/SemaCXX/co_await-range-for.cpp
@@ -0,0 +1,165 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \
+// RUN: -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \
+// RUN: -fblocks
+#include "Inputs/std-coroutine.h"
+
+using namespace std::experimental;
+
+
+template <class Begin>
+struct Awaiter {
+ bool await_ready();
+ void await_suspend(coroutine_handle<>);
+ Begin await_resume();
+};
+
+template <class Iter> struct BeginTag { BeginTag() = delete; };
+template <class Iter> struct IncTag { IncTag() = delete; };
+
+template <class Iter, bool Delete = false>
+struct CoawaitTag { CoawaitTag() = delete; };
+
+template <class T>
+struct Iter {
+ using value_type = T;
+ using reference = T &;
+ using pointer = T *;
+
+ IncTag<Iter> operator++();
+ reference operator*();
+ pointer operator->();
+};
+template <class T> bool operator==(Iter<T>, Iter<T>);
+template <class T> bool operator!=(Iter<T>, Iter<T>);
+
+template <class T>
+struct Range {
+ BeginTag<Iter<T>> begin();
+ Iter<T> end();
+};
+
+struct MyForLoopArrayAwaiter {
+ struct promise_type {
+ MyForLoopArrayAwaiter get_return_object() { return {}; }
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+ template <class T>
+ Awaiter<T *> await_transform(T *) = delete; // expected-note {{explicitly deleted}}
+ };
+};
+MyForLoopArrayAwaiter g() {
+ int arr[10] = {0};
+ for co_await(auto i : arr) {}
+ // expected-error@-1 {{call to deleted member function 'await_transform'}}
+ // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
+}
+
+struct ForLoopAwaiterBadBeginTransform {
+ struct promise_type {
+ ForLoopAwaiterBadBeginTransform get_return_object();
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+
+ template <class T>
+ Awaiter<T> await_transform(BeginTag<T>) = delete; // expected-note 1+ {{explicitly deleted}}
+
+ template <class T>
+ CoawaitTag<T> await_transform(IncTag<T>); // expected-note 1+ {{candidate}}
+ };
+};
+ForLoopAwaiterBadBeginTransform bad_begin() {
+ Range<int> R;
+ for co_await(auto i : R) {}
+ // expected-error@-1 {{call to deleted member function 'await_transform'}}
+ // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
+}
+template <class Dummy>
+ForLoopAwaiterBadBeginTransform bad_begin_template(Dummy) {
+ Range<Dummy> R;
+ for co_await(auto i : R) {}
+ // expected-error@-1 {{call to deleted member function 'await_transform'}}
+ // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
+}
+template ForLoopAwaiterBadBeginTransform bad_begin_template(int); // expected-note {{requested here}}
+
+template <class Iter>
+Awaiter<Iter> operator co_await(CoawaitTag<Iter, true>) = delete;
+// expected-note@-1 1+ {{explicitly deleted}}
+
+struct ForLoopAwaiterBadIncTransform {
+ struct promise_type {
+ ForLoopAwaiterBadIncTransform get_return_object();
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+
+ template <class T>
+ Awaiter<T> await_transform(BeginTag<T> e);
+
+ template <class T>
+ CoawaitTag<T, true> await_transform(IncTag<T>);
+ };
+};
+ForLoopAwaiterBadIncTransform bad_inc_transform() {
+ Range<float> R;
+ for co_await(auto i : R) {}
+ // expected-error@-1 {{overload resolution selected deleted operator 'co_await'}}
+ // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range<float>'}}
+}
+
+template <class Dummy>
+ForLoopAwaiterBadIncTransform bad_inc_transform_template(Dummy) {
+ Range<Dummy> R;
+ for co_await(auto i : R) {}
+ // expected-error@-1 {{overload resolution selected deleted operator 'co_await'}}
+ // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range<long>'}}
+}
+template ForLoopAwaiterBadIncTransform bad_inc_transform_template(long); // expected-note {{requested here}}
+
+// Ensure we mark and check the function as a coroutine even if it's
+// never instantiated.
+template <class T>
+constexpr void never_instant(T) {
+ static_assert(sizeof(T) != sizeof(T), "function should not be instantiated");
+ for co_await(auto i : foo(T{})) {}
+ // expected-error@-1 {{'co_await' cannot be used in a constexpr function}}
+}
+
+namespace NS {
+struct ForLoopAwaiterCoawaitLookup {
+ struct promise_type {
+ ForLoopAwaiterCoawaitLookup get_return_object();
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+ template <class T>
+ CoawaitTag<T, false> await_transform(BeginTag<T> e);
+ template <class T>
+ Awaiter<T> await_transform(IncTag<T>);
+ };
+};
+} // namespace NS
+using NS::ForLoopAwaiterCoawaitLookup;
+
+template <class T>
+ForLoopAwaiterCoawaitLookup test_coawait_lookup(T) {
+ Range<T> R;
+ for co_await(auto i : R) {}
+ // expected-error@-1 {{no member named 'await_ready' in 'CoawaitTag<Iter<int>, false>'}}
+}
+template ForLoopAwaiterCoawaitLookup test_coawait_lookup(int); // expected-note {{requested here}}
+
+// FIXME: This test should fail as well since the newly declared operator co_await
+// should not be found by lookup.
+namespace NS2 {
+template <class Iter>
+Awaiter<Iter> operator co_await(CoawaitTag<Iter, false>);
+}
+using NS2::operator co_await;
+template ForLoopAwaiterCoawaitLookup test_coawait_lookup(long);
diff --git a/test/SemaCXX/cxx1z-decomposition.cpp b/test/SemaCXX/cxx1z-decomposition.cpp
index d457ace5d844..7a4221784ad3 100644
--- a/test/SemaCXX/cxx1z-decomposition.cpp
+++ b/test/SemaCXX/cxx1z-decomposition.cpp
@@ -70,4 +70,10 @@ int error_recovery() {
return foobar_; // expected-error {{undeclared identifier 'foobar_'}}
}
+// PR32172
+template <class T> void dependent_foreach(T t) {
+ for (auto [a,b,c] : t)
+ a,b,c;
+}
+
// FIXME: by-value array copies
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 6ae45ff63332..725ac64cedb7 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -169,6 +169,13 @@ void N::f() { } // okay
struct Y; // expected-note{{forward declaration of 'Y'}}
Y::foo y; // expected-error{{incomplete type 'Y' named in nested name specifier}}
+namespace PR25156 {
+struct Y; // expected-note{{forward declaration of 'PR25156::Y'}}
+void foo() {
+ Y::~Y(); // expected-error{{incomplete type 'PR25156::Y' named in nested name specifier}}
+}
+}
+
X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}}
struct foo_S {
diff --git a/test/SemaCXX/warn-unused-lambda-capture.cpp b/test/SemaCXX/warn-unused-lambda-capture.cpp
index 48f8bfea7e9a..6ad8e26604a4 100644
--- a/test/SemaCXX/warn-unused-lambda-capture.cpp
+++ b/test/SemaCXX/warn-unused-lambda-capture.cpp
@@ -142,11 +142,14 @@ void test_templated() {
auto implicit_by_reference = [&] { i++; };
auto explicit_by_value_used = [i] { return i + 1; };
+ auto explicit_by_value_used_generic = [i](auto c) { return i + 1; };
auto explicit_by_value_used_void = [i] { (void)i; };
+
auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}}
auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
+ auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
auto explicit_by_reference_used = [&i] { i++; };
auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}}
@@ -161,6 +164,8 @@ void test_templated() {
auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}}
auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{};
auto explicit_initialized_value_with_side_effect = [j = side_effect()]{};
+ auto explicit_initialized_value_generic_used = [i = 1](auto c) mutable { i++; };
+ auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}}
auto nested = [&i] {
auto explicit_by_value_used = [i] { return i + 1; };
diff --git a/tools/clang-format/git-clang-format b/tools/clang-format/git-clang-format
index 71b9124149fc..60cd4fb25b63 100755
--- a/tools/clang-format/git-clang-format
+++ b/tools/clang-format/git-clang-format
@@ -324,6 +324,8 @@ def filter_by_extension(dictionary, allowed_extensions):
allowed_extensions = frozenset(allowed_extensions)
for filename in list(dictionary.keys()):
base_ext = filename.rsplit('.', 1)
+ if len(base_ext) == 1 and '' in allowed_extensions:
+ continue
if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions:
del dictionary[filename]
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 1ccf6cbd328e..f92096195081 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -7216,15 +7216,11 @@ static CXVersion convertVersion(VersionTuple In) {
return Out;
}
-static int getCursorPlatformAvailabilityForDecl(const Decl *D,
- int *always_deprecated,
- CXString *deprecated_message,
- int *always_unavailable,
- CXString *unavailable_message,
- CXPlatformAvailability *availability,
- int availability_size) {
+static void getCursorPlatformAvailabilityForDecl(
+ const Decl *D, int *always_deprecated, CXString *deprecated_message,
+ int *always_unavailable, CXString *unavailable_message,
+ SmallVectorImpl<AvailabilityAttr *> &AvailabilityAttrs) {
bool HadAvailAttr = false;
- int N = 0;
for (auto A : D->attrs()) {
if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(A)) {
HadAvailAttr = true;
@@ -7236,7 +7232,7 @@ static int getCursorPlatformAvailabilityForDecl(const Decl *D,
}
continue;
}
-
+
if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(A)) {
HadAvailAttr = true;
if (always_unavailable)
@@ -7247,38 +7243,71 @@ static int getCursorPlatformAvailabilityForDecl(const Decl *D,
}
continue;
}
-
+
if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(A)) {
+ AvailabilityAttrs.push_back(Avail);
HadAvailAttr = true;
- if (N < availability_size) {
- availability[N].Platform
- = cxstring::createDup(Avail->getPlatform()->getName());
- availability[N].Introduced = convertVersion(Avail->getIntroduced());
- availability[N].Deprecated = convertVersion(Avail->getDeprecated());
- availability[N].Obsoleted = convertVersion(Avail->getObsoleted());
- availability[N].Unavailable = Avail->getUnavailable();
- availability[N].Message = cxstring::createDup(Avail->getMessage());
- }
- ++N;
}
}
if (!HadAvailAttr)
if (const EnumConstantDecl *EnumConst = dyn_cast<EnumConstantDecl>(D))
return getCursorPlatformAvailabilityForDecl(
- cast<Decl>(EnumConst->getDeclContext()),
- always_deprecated,
- deprecated_message,
- always_unavailable,
- unavailable_message,
- availability,
- availability_size);
-
- return N;
+ cast<Decl>(EnumConst->getDeclContext()), always_deprecated,
+ deprecated_message, always_unavailable, unavailable_message,
+ AvailabilityAttrs);
+
+ if (AvailabilityAttrs.empty())
+ return;
+
+ std::sort(AvailabilityAttrs.begin(), AvailabilityAttrs.end(),
+ [](AvailabilityAttr *LHS, AvailabilityAttr *RHS) {
+ return LHS->getPlatform() > RHS->getPlatform();
+ });
+ ASTContext &Ctx = D->getASTContext();
+ auto It = std::unique(
+ AvailabilityAttrs.begin(), AvailabilityAttrs.end(),
+ [&Ctx](AvailabilityAttr *LHS, AvailabilityAttr *RHS) {
+ if (LHS->getPlatform() != RHS->getPlatform())
+ return false;
+
+ if (LHS->getIntroduced() == RHS->getIntroduced() &&
+ LHS->getDeprecated() == RHS->getDeprecated() &&
+ LHS->getObsoleted() == RHS->getObsoleted() &&
+ LHS->getMessage() == RHS->getMessage() &&
+ LHS->getReplacement() == RHS->getReplacement())
+ return true;
+
+ if ((!LHS->getIntroduced().empty() && !RHS->getIntroduced().empty()) ||
+ (!LHS->getDeprecated().empty() && !RHS->getDeprecated().empty()) ||
+ (!LHS->getObsoleted().empty() && !RHS->getObsoleted().empty()))
+ return false;
+
+ if (LHS->getIntroduced().empty() && !RHS->getIntroduced().empty())
+ LHS->setIntroduced(Ctx, RHS->getIntroduced());
+
+ if (LHS->getDeprecated().empty() && !RHS->getDeprecated().empty()) {
+ LHS->setDeprecated(Ctx, RHS->getDeprecated());
+ if (LHS->getMessage().empty())
+ LHS->setMessage(Ctx, RHS->getMessage());
+ if (LHS->getReplacement().empty())
+ LHS->setReplacement(Ctx, RHS->getReplacement());
+ }
+
+ if (LHS->getObsoleted().empty() && !RHS->getObsoleted().empty()) {
+ LHS->setObsoleted(Ctx, RHS->getObsoleted());
+ if (LHS->getMessage().empty())
+ LHS->setMessage(Ctx, RHS->getMessage());
+ if (LHS->getReplacement().empty())
+ LHS->setReplacement(Ctx, RHS->getReplacement());
+ }
+
+ return true;
+ });
+ AvailabilityAttrs.erase(It, AvailabilityAttrs.end());
}
-int clang_getCursorPlatformAvailability(CXCursor cursor,
- int *always_deprecated,
+int clang_getCursorPlatformAvailability(CXCursor cursor, int *always_deprecated,
CXString *deprecated_message,
int *always_unavailable,
CXString *unavailable_message,
@@ -7300,14 +7329,29 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
if (!D)
return 0;
- return getCursorPlatformAvailabilityForDecl(D, always_deprecated,
- deprecated_message,
- always_unavailable,
- unavailable_message,
- availability,
- availability_size);
+ SmallVector<AvailabilityAttr *, 8> AvailabilityAttrs;
+ getCursorPlatformAvailabilityForDecl(D, always_deprecated, deprecated_message,
+ always_unavailable, unavailable_message,
+ AvailabilityAttrs);
+ for (const auto &Avail :
+ llvm::enumerate(llvm::makeArrayRef(AvailabilityAttrs)
+ .take_front(availability_size))) {
+ availability[Avail.index()].Platform =
+ cxstring::createDup(Avail.value()->getPlatform()->getName());
+ availability[Avail.index()].Introduced =
+ convertVersion(Avail.value()->getIntroduced());
+ availability[Avail.index()].Deprecated =
+ convertVersion(Avail.value()->getDeprecated());
+ availability[Avail.index()].Obsoleted =
+ convertVersion(Avail.value()->getObsoleted());
+ availability[Avail.index()].Unavailable = Avail.value()->getUnavailable();
+ availability[Avail.index()].Message =
+ cxstring::createDup(Avail.value()->getMessage());
+ }
+
+ return AvailabilityAttrs.size();
}
-
+
void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) {
clang_disposeString(availability->Platform);
clang_disposeString(availability->Message);
diff --git a/unittests/AST/CommentLexer.cpp b/unittests/AST/CommentLexer.cpp
index 77ee22ffb43e..f96d6cd15f7a 100644
--- a/unittests/AST/CommentLexer.cpp
+++ b/unittests/AST/CommentLexer.cpp
@@ -320,9 +320,10 @@ TEST_F(CommentLexerTest, DoxygenCommand4) {
ASSERT_EQ(array_lengthof(Text), Toks.size());
for (size_t j = 0, e = Toks.size(); j != e; j++) {
- if(Toks[j].is(tok::text))
+ if(Toks[j].is(tok::text)) {
ASSERT_EQ(StringRef(Text[j]), Toks[j].getText())
<< "index " << i;
+ }
}
}
}
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 4f5579ce0def..7cfe5b9e3709 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -320,10 +320,12 @@ public:
ExpectedName(ExpectedName) {}
void onEndOfTranslationUnit() override {
- if (ExpectedCount != -1)
+ if (ExpectedCount != -1) {
EXPECT_EQ(ExpectedCount, Count);
- if (!ExpectedName.empty())
+ }
+ if (!ExpectedName.empty()) {
EXPECT_EQ(ExpectedName, Name);
+ }
Count = 0;
Name.clear();
}
@@ -346,8 +348,9 @@ public:
}
BoundNodes::IDToNodeMap::const_iterator I = M.find(Id);
EXPECT_NE(M.end(), I);
- if (I != M.end())
+ if (I != M.end()) {
EXPECT_EQ(Nodes->getNodeAs<T>(Id), I->second.get<T>());
+ }
return true;
}
EXPECT_TRUE(M.count(Id) == 0 ||
diff --git a/unittests/Basic/VirtualFileSystemTest.cpp b/unittests/Basic/VirtualFileSystemTest.cpp
index 0856b17791fa..40add2195b58 100644
--- a/unittests/Basic/VirtualFileSystemTest.cpp
+++ b/unittests/Basic/VirtualFileSystemTest.cpp
@@ -300,8 +300,9 @@ struct ScopedDir {
EXPECT_FALSE(EC);
}
~ScopedDir() {
- if (Path != "")
+ if (Path != "") {
EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
+ }
}
operator StringRef() { return Path.str(); }
};
@@ -316,8 +317,9 @@ struct ScopedLink {
EXPECT_FALSE(EC);
}
~ScopedLink() {
- if (Path != "")
+ if (Path != "") {
EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
+ }
}
operator StringRef() { return Path.str(); }
};
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 64e963db4cfd..f4937171038d 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -1310,6 +1310,141 @@ TEST_F(FormatTest, FormatsNamespaces) {
Style));
}
+TEST_F(FormatTest, FormatsCompactNamespaces) {
+ FormatStyle Style = getLLVMStyle();
+ Style.CompactNamespaces = true;
+
+ verifyFormat("namespace A { namespace B {\n"
+ "}} // namespace A::B",
+ Style);
+
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}} // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "} // namespace in\n"
+ "} // namespace out",
+ Style));
+
+ // Only namespaces which have both consecutive opening and end get compacted
+ EXPECT_EQ("namespace out {\n"
+ "namespace in1 {\n"
+ "} // namespace in1\n"
+ "namespace in2 {\n"
+ "} // namespace in2\n"
+ "} // namespace out",
+ format("namespace out {\n"
+ "namespace in1 {\n"
+ "} // namespace in1\n"
+ "namespace in2 {\n"
+ "} // namespace in2\n"
+ "} // namespace out",
+ Style));
+
+ EXPECT_EQ("namespace out {\n"
+ "int i;\n"
+ "namespace in {\n"
+ "int j;\n"
+ "} // namespace in\n"
+ "int k;\n"
+ "} // namespace out",
+ format("namespace out { int i;\n"
+ "namespace in { int j; } // namespace in\n"
+ "int k; } // namespace out",
+ Style));
+
+ EXPECT_EQ("namespace A { namespace B { namespace C {\n"
+ "}}} // namespace A::B::C\n",
+ format("namespace A { namespace B {\n"
+ "namespace C {\n"
+ "}} // namespace B::C\n"
+ "} // namespace A\n",
+ Style));
+
+ Style.ColumnLimit = 40;
+ EXPECT_EQ("namespace aaaaaaaaaa {\n"
+ "namespace bbbbbbbbbb {\n"
+ "}} // namespace aaaaaaaaaa::bbbbbbbbbb",
+ format("namespace aaaaaaaaaa {\n"
+ "namespace bbbbbbbbbb {\n"
+ "} // namespace bbbbbbbbbb\n"
+ "} // namespace aaaaaaaaaa",
+ Style));
+
+ EXPECT_EQ("namespace aaaaaa { namespace bbbbbb {\n"
+ "namespace cccccc {\n"
+ "}}} // namespace aaaaaa::bbbbbb::cccccc",
+ format("namespace aaaaaa {\n"
+ "namespace bbbbbb {\n"
+ "namespace cccccc {\n"
+ "} // namespace cccccc\n"
+ "} // namespace bbbbbb\n"
+ "} // namespace aaaaaa",
+ Style));
+ Style.ColumnLimit = 80;
+
+ // Extra semicolon after 'inner' closing brace prevents merging
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}; } // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "}; // namespace in\n"
+ "} // namespace out",
+ Style));
+
+ // Extra semicolon after 'outer' closing brace is conserved
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}}; // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "} // namespace in\n"
+ "}; // namespace out",
+ Style));
+
+ Style.NamespaceIndentation = FormatStyle::NI_All;
+ EXPECT_EQ("namespace out { namespace in {\n"
+ " int i;\n"
+ "}} // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "int i;\n"
+ "} // namespace in\n"
+ "} // namespace out",
+ Style));
+ EXPECT_EQ("namespace out { namespace mid {\n"
+ " namespace in {\n"
+ " int j;\n"
+ " } // namespace in\n"
+ " int k;\n"
+ "}} // namespace out::mid",
+ format("namespace out { namespace mid {\n"
+ "namespace in { int j; } // namespace in\n"
+ "int k; }} // namespace out::mid",
+ Style));
+
+ Style.NamespaceIndentation = FormatStyle::NI_Inner;
+ EXPECT_EQ("namespace out { namespace in {\n"
+ " int i;\n"
+ "}} // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "int i;\n"
+ "} // namespace in\n"
+ "} // namespace out",
+ Style));
+ EXPECT_EQ("namespace out { namespace mid { namespace in {\n"
+ " int i;\n"
+ "}}} // namespace out::mid::in",
+ format("namespace out {\n"
+ "namespace mid {\n"
+ "namespace in {\n"
+ "int i;\n"
+ "} // namespace in\n"
+ "} // namespace mid\n"
+ "} // namespace out",
+ Style));
+}
+
TEST_F(FormatTest, FormatsExternC) { verifyFormat("extern \"C\" {\nint a;"); }
TEST_F(FormatTest, FormatsInlineASM) {
@@ -6239,6 +6374,35 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
getLLVMStyleWithColumns(23));
}
+TEST_F(FormatTest, PullEmptyFunctionDefinitionsIntoSingleLine) {
+ FormatStyle MergeEmptyOnly = getLLVMStyle();
+ MergeEmptyOnly.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
+ verifyFormat("class C {\n"
+ " int f() {}\n"
+ "};",
+ MergeEmptyOnly);
+ verifyFormat("class C {\n"
+ " int f() {\n"
+ " return 42;\n"
+ " }\n"
+ "};",
+ MergeEmptyOnly);
+ verifyFormat("int f() {}", MergeEmptyOnly);
+ verifyFormat("int f() {\n"
+ " return 42;\n"
+ "}",
+ MergeEmptyOnly);
+
+ // Also verify behavior when BraceWrapping.AfterFunction = true
+ MergeEmptyOnly.BreakBeforeBraces = FormatStyle::BS_Custom;
+ MergeEmptyOnly.BraceWrapping.AfterFunction = true;
+ verifyFormat("int f() {}", MergeEmptyOnly);
+ verifyFormat("class C {\n"
+ " int f() {}\n"
+ "};",
+ MergeEmptyOnly);
+}
+
TEST_F(FormatTest, PullInlineFunctionDefinitionsIntoSingleLine) {
FormatStyle MergeInlineOnly = getLLVMStyle();
MergeInlineOnly.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
@@ -6250,6 +6414,101 @@ TEST_F(FormatTest, PullInlineFunctionDefinitionsIntoSingleLine) {
" return 42;\n"
"}",
MergeInlineOnly);
+
+ // SFS_Inline implies SFS_Empty
+ verifyFormat("class C {\n"
+ " int f() {}\n"
+ "};",
+ MergeInlineOnly);
+ verifyFormat("int f() {}", MergeInlineOnly);
+
+ // Also verify behavior when BraceWrapping.AfterFunction = true
+ MergeInlineOnly.BreakBeforeBraces = FormatStyle::BS_Custom;
+ MergeInlineOnly.BraceWrapping.AfterFunction = true;
+ verifyFormat("class C {\n"
+ " int f() { return 42; }\n"
+ "};",
+ MergeInlineOnly);
+ verifyFormat("int f()\n"
+ "{\n"
+ " return 42;\n"
+ "}",
+ MergeInlineOnly);
+
+ // SFS_Inline implies SFS_Empty
+ verifyFormat("int f() {}", MergeInlineOnly);
+ verifyFormat("class C {\n"
+ " int f() {}\n"
+ "};",
+ MergeInlineOnly);
+}
+
+TEST_F(FormatTest, SplitEmptyFunctionBody) {
+ FormatStyle Style = getLLVMStyle();
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterFunction = true;
+ Style.BraceWrapping.SplitEmptyFunctionBody = false;
+ Style.ColumnLimit = 40;
+
+ verifyFormat("int f()\n"
+ "{}",
+ Style);
+ verifyFormat("int f()\n"
+ "{\n"
+ " return 42;\n"
+ "}",
+ Style);
+ verifyFormat("int f()\n"
+ "{\n"
+ " // some comment\n"
+ "}",
+ Style);
+
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
+ verifyFormat("int f() {}", Style);
+ verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
+ "{}",
+ Style);
+ verifyFormat("int f()\n"
+ "{\n"
+ " return 0;\n"
+ "}",
+ Style);
+
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
+ verifyFormat("class Foo {\n"
+ " int f() {}\n"
+ "};\n",
+ Style);
+ verifyFormat("class Foo {\n"
+ " int f() { return 0; }\n"
+ "};\n",
+ Style);
+ verifyFormat("class Foo {\n"
+ " int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
+ " {}\n"
+ "};\n",
+ Style);
+ verifyFormat("class Foo {\n"
+ " int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
+ " {\n"
+ " return 0;\n"
+ " }\n"
+ "};\n",
+ Style);
+
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
+ verifyFormat("int f() {}", Style);
+ verifyFormat("int f() { return 0; }", Style);
+ verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
+ "{}",
+ Style);
+ verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
+ "{\n"
+ " return 0;\n"
+ "}",
+ Style);
}
TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
@@ -8927,6 +9186,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
CHECK_PARSE_BOOL(BreakStringLiterals);
CHECK_PARSE_BOOL(BreakBeforeInheritanceComma)
+ CHECK_PARSE_BOOL(CompactNamespaces);
CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine);
CHECK_PARSE_BOOL(DerivePointerAlignment);
CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding");
@@ -8960,6 +9220,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeCatch);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeElse);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, IndentBraces);
+ CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyFunctionBody);
}
#undef CHECK_PARSE_BOOL
diff --git a/unittests/Format/NamespaceEndCommentsFixerTest.cpp b/unittests/Format/NamespaceEndCommentsFixerTest.cpp
index 6c2d36985290..92f342162938 100644
--- a/unittests/Format/NamespaceEndCommentsFixerTest.cpp
+++ b/unittests/Format/NamespaceEndCommentsFixerTest.cpp
@@ -185,6 +185,41 @@ TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) {
"}\n"
"}"));
+ // Add comment for namespaces which will be 'compacted'
+ FormatStyle CompactNamespacesStyle = getLLVMStyle();
+ CompactNamespacesStyle.CompactNamespaces = true;
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "}}// namespace out::in",
+ fixNamespaceEndComments("namespace out { namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "}}",
+ CompactNamespacesStyle));
+ EXPECT_EQ("namespace out {\n"
+ "namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "}\n"
+ "}// namespace out::in",
+ fixNamespaceEndComments("namespace out {\n"
+ "namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "}\n"
+ "}",
+ CompactNamespacesStyle));
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "};}// namespace out::in",
+ fixNamespaceEndComments("namespace out { namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "};}",
+ CompactNamespacesStyle));
+
// Adds an end comment after a semicolon.
EXPECT_EQ("namespace {\n"
" int i;\n"
@@ -388,6 +423,27 @@ TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndLineComment) {
fixNamespaceEndComments("namespace A {} // namespace"));
EXPECT_EQ("namespace A {}; // namespace A",
fixNamespaceEndComments("namespace A {}; // namespace"));
+
+ // Update invalid comments for compacted namespaces.
+ FormatStyle CompactNamespacesStyle = getLLVMStyle();
+ CompactNamespacesStyle.CompactNamespaces = true;
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}} // namespace out::in",
+ fixNamespaceEndComments("namespace out { namespace in {\n"
+ "}} // namespace out",
+ CompactNamespacesStyle));
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}} // namespace out::in",
+ fixNamespaceEndComments("namespace out { namespace in {\n"
+ "}} // namespace in",
+ CompactNamespacesStyle));
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}\n"
+ "} // namespace out::in",
+ fixNamespaceEndComments("namespace out { namespace in {\n"
+ "}// banamespace in\n"
+ "} // namespace out",
+ CompactNamespacesStyle));
}
TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndBlockComment) {
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
index e2507d3580d3..a887c22bd301 100644
--- a/unittests/Lex/LexerTest.cpp
+++ b/unittests/Lex/LexerTest.cpp
@@ -18,6 +18,8 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/MacroArgs.h"
+#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
@@ -41,26 +43,33 @@ protected:
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
}
- std::vector<Token> Lex(StringRef Source) {
+ std::unique_ptr<Preprocessor> CreatePP(StringRef Source,
+ TrivialModuleLoader &ModLoader) {
std::unique_ptr<llvm::MemoryBuffer> Buf =
llvm::MemoryBuffer::getMemBuffer(Source);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
- TrivialModuleLoader ModLoader;
MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
- Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, PCMCache, HeaderInfo, ModLoader,
- /*IILookup =*/nullptr,
- /*OwnsHeaderSearch =*/false);
- PP.Initialize(*Target);
- PP.EnterMainSourceFile();
+ std::unique_ptr<Preprocessor> PP = llvm::make_unique<Preprocessor>(
+ std::make_shared<PreprocessorOptions>(), Diags, LangOpts, SourceMgr,
+ PCMCache, HeaderInfo, ModLoader,
+ /*IILookup =*/nullptr,
+ /*OwnsHeaderSearch =*/false);
+ PP->Initialize(*Target);
+ PP->EnterMainSourceFile();
+ return PP;
+ }
+
+ std::vector<Token> Lex(StringRef Source) {
+ TrivialModuleLoader ModLoader;
+ auto PP = CreatePP(Source, ModLoader);
std::vector<Token> toks;
while (1) {
Token tok;
- PP.Lex(tok);
+ PP->Lex(tok);
if (tok.is(tok::eof))
break;
toks.push_back(tok);
@@ -365,4 +374,50 @@ TEST_F(LexerTest, DontMergeMacroArgsFromDifferentMacroFiles) {
EXPECT_EQ(SourceMgr.getFileIDSize(SourceMgr.getFileID(helper1ArgLoc)), 8U);
}
+TEST_F(LexerTest, DontOverallocateStringifyArgs) {
+ TrivialModuleLoader ModLoader;
+ auto PP = CreatePP("\"StrArg\", 5, 'C'", ModLoader);
+
+ llvm::BumpPtrAllocator Allocator;
+ std::array<IdentifierInfo *, 3> ArgList;
+ MacroInfo *MI = PP->AllocateMacroInfo({});
+ MI->setIsFunctionLike();
+ MI->setArgumentList(ArgList, Allocator);
+ EXPECT_EQ(3u, MI->getNumArgs());
+ EXPECT_TRUE(MI->isFunctionLike());
+
+ Token Eof;
+ Eof.setKind(tok::eof);
+ std::vector<Token> ArgTokens;
+ while (1) {
+ Token tok;
+ PP->Lex(tok);
+ if (tok.is(tok::eof)) {
+ ArgTokens.push_back(Eof);
+ break;
+ }
+ if (tok.is(tok::comma))
+ ArgTokens.push_back(Eof);
+ else
+ ArgTokens.push_back(tok);
+ }
+
+ auto MacroArgsDeleter = [&PP](MacroArgs *M) { M->destroy(*PP); };
+ std::unique_ptr<MacroArgs, decltype(MacroArgsDeleter)> MA(
+ MacroArgs::create(MI, ArgTokens, false, *PP), MacroArgsDeleter);
+ Token Result = MA->getStringifiedArgument(0, *PP, {}, {});
+ EXPECT_EQ(tok::string_literal, Result.getKind());
+ EXPECT_STREQ("\"\\\"StrArg\\\"\"", Result.getLiteralData());
+ Result = MA->getStringifiedArgument(1, *PP, {}, {});
+ EXPECT_EQ(tok::string_literal, Result.getKind());
+ EXPECT_STREQ("\"5\"", Result.getLiteralData());
+ Result = MA->getStringifiedArgument(2, *PP, {}, {});
+ EXPECT_EQ(tok::string_literal, Result.getKind());
+ EXPECT_STREQ("\"'C'\"", Result.getLiteralData());
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+ EXPECT_DEATH(MA->getStringifiedArgument(3, *PP, {}, {}),
+ "Invalid argument number!");
+#endif
+}
+
} // anonymous namespace
diff --git a/unittests/Tooling/LookupTest.cpp b/unittests/Tooling/LookupTest.cpp
index cc3922d01b51..f42f31e9dd99 100644
--- a/unittests/Tooling/LookupTest.cpp
+++ b/unittests/Tooling/LookupTest.cpp
@@ -143,8 +143,9 @@ TEST(LookupTest, replaceNestedClassName) {
Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) {
// Filter Types by name since there are other `RecordTypeLoc` in the test
// file.
- if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo")
+ if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
EXPECT_EQ("x::Bar", replaceRecordTypeLoc(Type, "::a::x::Bar"));
+ }
};
Visitor.runOver("namespace a { namespace b {\n"
"class Foo;\n"
@@ -155,8 +156,9 @@ TEST(LookupTest, replaceNestedClassName) {
// Filter Types by name since there are other `RecordTypeLoc` in the test
// file.
// `a::b::Foo` in using shadow decl is not `TypeLoc`.
- if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo")
+ if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
EXPECT_EQ("Bar", replaceRecordTypeLoc(Type, "::a::x::Bar"));
+ }
};
Visitor.runOver("namespace a { namespace b { class Foo {}; } }\n"
"namespace c { using a::b::Foo; Foo f();; }\n");