aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-09 21:23:21 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-09 21:23:21 +0000
commitfdc82ccb3f2b23a89e7002fe8238e1422b00f96a (patch)
treef189aa0a3010e0eb212970b8eadf0a8b098985ea
parent6694ed095d6b27a2c92ec4fd63664fcd88a05749 (diff)
downloadsrc-fdc82ccb3f2b23a89e7002fe8238e1422b00f96a.tar.gz
src-fdc82ccb3f2b23a89e7002fe8238e1422b00f96a.zip
Vendor import of clang trunk r291476:vendor/clang/clang-trunk-r291476
Notes
Notes: svn path=/vendor/clang/dist/; revision=311820 svn path=/vendor/clang/clang-trunk-r291476/; revision=311821; tag=vendor/clang/clang-trunk-r291476
-rw-r--r--docs/ReleaseNotes.rst4
-rw-r--r--include/clang/AST/Expr.h3
-rw-r--r--include/clang/Basic/Attr.td27
-rw-r--r--include/clang/Basic/AttrDocs.td59
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticGroups.td4
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td15
-rw-r--r--include/clang/Basic/LangOptions.def1
-rw-r--r--include/clang/Driver/CC1Options.td3
-rw-r--r--include/clang/Frontend/CodeGenOptions.def1
-rw-r--r--include/clang/Frontend/FrontendActions.h2
-rw-r--r--include/clang/Index/IndexSymbol.h9
-rw-r--r--include/clang/Sema/Initialization.h4
-rw-r--r--include/clang/Sema/Overload.h141
-rw-r--r--include/clang/Sema/Sema.h120
-rw-r--r--include/clang/StaticAnalyzer/Checkers/Checkers.td8
-rw-r--r--lib/AST/ExprConstant.cpp84
-rw-r--r--lib/AST/MicrosoftMangle.cpp18
-rw-r--r--lib/CodeGen/BackendUtil.cpp59
-rw-r--r--lib/CodeGen/CGCleanup.h2
-rw-r--r--lib/CodeGen/CGException.cpp8
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp3
-rw-r--r--lib/Driver/ToolChains.cpp1
-rw-r--r--lib/Driver/Tools.cpp1
-rw-r--r--lib/Format/TokenAnnotator.cpp10
-rw-r--r--lib/Format/UnwrappedLineParser.cpp18
-rw-r--r--lib/Frontend/CompilerInvocation.cpp1
-rw-r--r--lib/Frontend/FrontendActions.cpp6
-rw-r--r--lib/Index/IndexSymbol.cpp18
-rw-r--r--lib/Lex/PPDirectives.cpp17
-rw-r--r--lib/Parse/ParseDecl.cpp7
-rw-r--r--lib/Parse/ParseInit.cpp4
-rw-r--r--lib/Sema/SemaChecking.cpp3
-rw-r--r--lib/Sema/SemaDeclAttr.cpp109
-rw-r--r--lib/Sema/SemaDeclCXX.cpp52
-rw-r--r--lib/Sema/SemaExpr.cpp284
-rw-r--r--lib/Sema/SemaExprMember.cpp1
-rw-r--r--lib/Sema/SemaInit.cpp7
-rw-r--r--lib/Sema/SemaLambda.cpp3
-rw-r--r--lib/Sema/SemaLookup.cpp3
-rw-r--r--lib/Sema/SemaOverload.cpp632
-rw-r--r--lib/Sema/SemaTemplate.cpp5
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp138
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp75
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp64
-rw-r--r--lib/Serialization/ASTWriter.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt1
-rw-r--r--lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp842
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp9
-rw-r--r--test/Analysis/Inputs/system-header-simulator-cxx.h64
-rw-r--r--test/Analysis/diagnostics/explicit-suppression.cpp2
-rw-r--r--test/Analysis/inlining/stl.cpp3
-rw-r--r--test/Analysis/iterator-past-end.cpp205
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp30
-rw-r--r--test/CXX/drs/dr13xx.cpp130
-rw-r--r--test/CXX/drs/dr19xx.cpp9
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp4
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp13
-rw-r--r--test/CXX/temp/temp.param/p5.cpp10
-rw-r--r--test/CodeGen/lifetime2.c2
-rw-r--r--test/CodeGen/thinlto_backend.ll8
-rw-r--r--test/CodeGenCXX/arm.cpp9
-rw-r--r--test/CodeGenCXX/debug-info-class.cpp15
-rw-r--r--test/CodeGenCXX/dllexport-ctor-closure.cpp82
-rw-r--r--test/CodeGenCXX/dllexport.cpp51
-rw-r--r--test/CodeGenCXX/eh-aggregate-copy-destroy.cpp6
-rw-r--r--test/CodeGenCXX/exceptions.cpp104
-rw-r--r--test/CodeGenCXX/goto.cpp7
-rw-r--r--test/Driver/B-opt.c8
-rw-r--r--test/Driver/coverage-ld.c8
-rw-r--r--test/Driver/cross-linux.c18
-rw-r--r--test/Driver/fuchsia.c2
-rw-r--r--test/Driver/fuchsia.cpp2
-rw-r--r--test/Driver/fuse-ld.c4
-rw-r--r--test/Driver/instrprof-ld.c24
-rw-r--r--test/Driver/mips-mti-linux.c4
-rw-r--r--test/Driver/netbsd.c36
-rw-r--r--test/Driver/netbsd.cpp40
-rw-r--r--test/Driver/nostdlib.c4
-rw-r--r--test/Driver/prefixed-tools.c4
-rw-r--r--test/Driver/sanitizer-ld.c94
-rw-r--r--test/Driver/windows-cross.c14
-rw-r--r--test/Index/Core/index-source.cpp11
-rw-r--r--test/Misc/diag-template-diffing.cpp6
-rw-r--r--test/Modules/Inputs/pch-with-module-name/A.h1
-rw-r--r--test/Modules/Inputs/pch-with-module-name/C.h1
-rw-r--r--test/Modules/Inputs/pch-with-module-name/C.m1
-rw-r--r--test/Modules/Inputs/pch-with-module-name/D.h1
-rw-r--r--test/Modules/Inputs/pch-with-module-name/module.modulemap9
-rw-r--r--test/Modules/Inputs/pch-with-module-name/test.h1
-rw-r--r--test/Modules/pch-with-module-name.m5
-rw-r--r--test/OpenMP/atomic_codegen.cpp11
-rw-r--r--test/OpenMP/threadprivate_codegen.cpp2
-rw-r--r--test/Sema/diagnose_if.c152
-rw-r--r--test/SemaCXX/PR10177.cpp9
-rw-r--r--test/SemaCXX/attr-mode-tmpl.cpp2
-rw-r--r--test/SemaCXX/attr-noreturn.cpp10
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp4
-rw-r--r--test/SemaCXX/cxx1z-constexpr-lambdas.cpp114
-rw-r--r--test/SemaCXX/diagnose_if.cpp460
-rw-r--r--test/SemaCXX/enable_if.cpp8
-rw-r--r--test/SemaCXX/implicit-exception-spec.cpp32
-rw-r--r--test/SemaCXX/libstdcxx_gets_hack.cpp28
-rw-r--r--test/SemaCXX/member-init.cpp24
-rw-r--r--test/SemaCXX/overload-call.cpp2
-rw-r--r--test/SemaCXX/overload-member-call.cpp2
-rw-r--r--test/SemaCXX/undefined-internal.cpp11
-rw-r--r--test/SemaTemplate/alias-templates.cpp10
-rw-r--r--test/SemaTemplate/constexpr-instantiate.cpp91
-rw-r--r--test/SemaTemplate/deduction.cpp30
-rw-r--r--test/SemaTemplate/default-arguments-cxx0x.cpp2
-rw-r--r--test/SemaTemplate/instantiate-init.cpp3
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp8
-rw-r--r--tools/c-index-test/core_main.cpp2
-rw-r--r--tools/driver/CMakeLists.txt20
-rw-r--r--unittests/Format/FormatTest.cpp4
-rw-r--r--unittests/Format/FormatTestJS.cpp20
-rw-r--r--www/cxx_dr_status.html8
118 files changed, 4186 insertions, 834 deletions
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index 11ee88f4ae20..b15d9a5a147c 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -47,6 +47,10 @@ sections with improvements to Clang's support for those languages.
Major New Features
------------------
+- The ``diagnose_if`` attribute has been added to clang. This attribute allows
+ clang to emit a warning or error if a function call meets one or more
+ user-specified conditions.
+
- ...
Improvements to Clang's diagnostics
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 41ae6d2b721e..56b99ccd8971 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -651,7 +651,8 @@ public:
/// constant.
bool EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
const FunctionDecl *Callee,
- ArrayRef<const Expr*> Args) const;
+ ArrayRef<const Expr*> Args,
+ const Expr *This = nullptr) const;
/// \brief If the current Expr is a pointer, this will try to statically
/// determine the number of bytes available where the pointer is pointing.
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index e3c2b0e45d3d..fa60d512a6ff 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -140,12 +140,15 @@ class Argument<string name, bit optional, bit fake = 0> {
bit Fake = fake;
}
-class BoolArgument<string name, bit opt = 0> : Argument<name, opt>;
+class BoolArgument<string name, bit opt = 0, bit fake = 0> : Argument<name, opt,
+ fake>;
class IdentifierArgument<string name, bit opt = 0> : Argument<name, opt>;
class IntArgument<string name, bit opt = 0> : Argument<name, opt>;
class StringArgument<string name, bit opt = 0> : Argument<name, opt>;
class ExprArgument<string name, bit opt = 0> : Argument<name, opt>;
-class FunctionArgument<string name, bit opt = 0> : Argument<name, opt>;
+class FunctionArgument<string name, bit opt = 0, bit fake = 0> : Argument<name,
+ opt,
+ fake>;
class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
class VariadicUnsignedArgument<string name> : Argument<name, 1>;
@@ -1591,6 +1594,26 @@ def Unavailable : InheritableAttr {
let Documentation = [Undocumented];
}
+def DiagnoseIf : InheritableAttr {
+ let Spellings = [GNU<"diagnose_if">];
+ let Subjects = SubjectList<[Function]>;
+ let Args = [ExprArgument<"Cond">, StringArgument<"Message">,
+ EnumArgument<"DiagnosticType",
+ "DiagnosticType",
+ ["error", "warning"],
+ ["DT_Error", "DT_Warning"]>,
+ BoolArgument<"ArgDependent", 0, /*fake*/ 1>,
+ FunctionArgument<"Parent", 0, /*fake*/ 1>];
+ let DuplicatesAllowedWhileMerging = 1;
+ let LateParsed = 1;
+ let AdditionalMembers = [{
+ bool isError() const { return diagnosticType == DT_Error; }
+ bool isWarning() const { return diagnosticType == DT_Warning; }
+ }];
+ let TemplateDependent = 1;
+ let Documentation = [DiagnoseIfDocs];
+}
+
def ArcWeakrefUnavailable : InheritableAttr {
let Spellings = [GNU<"objc_arc_weak_reference_unavailable">];
let Subjects = SubjectList<[ObjCInterface], ErrorDiag>;
diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td
index b57833a15f31..49b0a533cec3 100644
--- a/include/clang/Basic/AttrDocs.td
+++ b/include/clang/Basic/AttrDocs.td
@@ -378,6 +378,65 @@ template instantiation, so the value for ``T::number`` is known.
}];
}
+def DiagnoseIfDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The ``diagnose_if`` attribute can be placed on function declarations to emit
+warnings or errors at compile-time if calls to the attributed function meet
+certain user-defined criteria. For example:
+
+.. code-block:: c
+ void abs(int a)
+ __attribute__((diagnose_if(a >= 0, "Redundant abs call", "warning")));
+ void must_abs(int a)
+ __attribute__((diagnose_if(a >= 0, "Redundant abs call", "error")));
+
+ int val = abs(1); // warning: Redundant abs call
+ int val2 = must_abs(1); // error: Redundant abs call
+ int val3 = abs(val);
+ int val4 = must_abs(val); // Because run-time checks are not emitted for
+ // diagnose_if attributes, this executes without
+ // issue.
+
+
+``diagnose_if`` is closely related to ``enable_if``, with a few key differences:
+
+* Overload resolution is not aware of ``diagnose_if`` attributes: they're
+ considered only after we select the best candidate from a given candidate set.
+* Function declarations that differ only in their ``diagnose_if`` attributes are
+ considered to be redeclarations of the same function (not overloads).
+* If the condition provided to ``diagnose_if`` cannot be evaluated, no
+ diagnostic will be emitted.
+
+Otherwise, ``diagnose_if`` is essentially the logical negation of ``enable_if``.
+
+As a result of bullet number two, ``diagnose_if`` attributes will stack on the
+same function. For example:
+
+.. code-block:: c
+
+ int foo() __attribute__((diagnose_if(1, "diag1", "warning")));
+ int foo() __attribute__((diagnose_if(1, "diag2", "warning")));
+
+ int bar = foo(); // warning: diag1
+ // warning: diag2
+ int (*fooptr)(void) = foo; // warning: diag1
+ // warning: diag2
+
+ constexpr int supportsAPILevel(int N) { return N < 5; }
+ int baz(int a)
+ __attribute__((diagnose_if(!supportsAPILevel(10),
+ "Upgrade to API level 10 to use baz", "error")));
+ int baz(int a)
+ __attribute__((diagnose_if(!a, "0 is not recommended.", "warning")));
+
+ int (*bazptr)(int) = baz; // error: Upgrade to API level 10 to use baz
+ int v = baz(0); // error: Upgrade to API level 10 to use baz
+
+Query for this feature with ``__has_attribute(diagnose_if)``.
+ }];
+}
+
def PassObjectSizeDocs : Documentation {
let Category = DocCatVariable; // Technically it's a parameter doc, but eh.
let Content = [{
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index e8180eb1db48..af0612a829e1 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -161,6 +161,8 @@ def ext_old_implicitly_unsigned_long_cxx : ExtWarn<
InGroup<CXX11Compat>;
def ext_clang_enable_if : Extension<"'enable_if' is a clang extension">,
InGroup<GccCompat>;
+def ext_clang_diagnose_if : Extension<"'diagnose_if' is a clang extension">,
+ InGroup<GccCompat>;
// SEH
def err_seh_expected_handler : Error<
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index ba82b36cea31..4173d03de9f0 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -495,6 +495,7 @@ def UnusedPropertyIvar : DiagGroup<"unused-property-ivar">;
def UnusedGetterReturnValue : DiagGroup<"unused-getter-return-value">;
def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">;
def UserDefinedLiterals : DiagGroup<"user-defined-literals">;
+def UserDefinedWarnings : DiagGroup<"user-defined-warnings">;
def Reorder : DiagGroup<"reorder">;
def UndeclaredSelector : DiagGroup<"undeclared-selector">;
def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">;
@@ -683,7 +684,8 @@ def Most : DiagGroup<"most", [
OverloadedVirtual,
PrivateExtern,
SelTypeCast,
- ExternCCompat
+ ExternCCompat,
+ UserDefinedWarnings
]>;
// Thread Safety warnings
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 0807bba45fc4..6a8933f23ecd 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2141,8 +2141,11 @@ def err_constexpr_local_var_no_init : Error<
def ext_constexpr_function_never_constant_expr : ExtWarn<
"constexpr %select{function|constructor}0 never produces a "
"constant expression">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError;
-def err_enable_if_never_constant_expr : Error<
- "'enable_if' attribute expression never produces a constant expression">;
+def err_attr_cond_never_constant_expr : Error<
+ "%0 attribute expression never produces a constant expression">;
+def err_diagnose_if_invalid_diagnostic_type : Error<
+ "invalid diagnostic type for 'diagnose_if'; use \"error\" or \"warning\" "
+ "instead">;
def err_constexpr_body_no_return : Error<
"no return statement in constexpr function">;
def err_constexpr_return_missing_expr : Error<
@@ -3333,6 +3336,9 @@ def note_ovl_candidate : Note<"candidate "
def note_ovl_candidate_inherited_constructor : Note<
"constructor from base class %0 inherited here">;
+def note_ovl_candidate_inherited_constructor_slice : Note<
+ "constructor inherited from base class cannot be used to initialize from "
+ "an argument of the derived class type">;
def note_ovl_candidate_illegal_constructor : Note<
"candidate %select{constructor|template}0 ignored: "
"instantiation %select{takes|would take}0 its own class type by value">;
@@ -3366,7 +3372,9 @@ def note_ovl_candidate_disabled_by_enable_if : Note<
def note_ovl_candidate_has_pass_object_size_params: Note<
"candidate address cannot be taken because parameter %0 has "
"pass_object_size attribute">;
-def note_ovl_candidate_disabled_by_enable_if_attr : Note<
+def err_diagnose_if_succeeded : Error<"%0">;
+def warn_diagnose_if_succeeded : Warning<"%0">, InGroup<UserDefinedWarnings>;
+def note_ovl_candidate_disabled_by_function_cond_attr : Note<
"candidate disabled: %0">;
def note_ovl_candidate_disabled_by_extension : Note<
"candidate disabled due to OpenCL extension">;
@@ -4395,6 +4403,7 @@ def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to th
def err_undeclared_use : Error<"use of undeclared %0">;
def warn_deprecated : Warning<"%0 is deprecated">,
InGroup<DeprecatedDeclarations>;
+def note_from_diagnose_if : Note<"from 'diagnose_if' attribute on %0:">;
def warn_property_method_deprecated :
Warning<"property access is using %0 method which is deprecated">,
InGroup<DeprecatedDeclarations>;
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index 47db50c52b74..d944a9d78ab9 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -146,6 +146,7 @@ LANGOPT(Modules , 1, 0, "modules extension to C")
COMPATIBLE_LANGOPT(ModulesTS , 1, 0, "C++ Modules TS")
BENIGN_ENUM_LANGOPT(CompilingModule, CompilingModuleKind, 2, CMK_None,
"compiling a module interface")
+BENIGN_LANGOPT(CompilingPCH, 1, 0, "building a pch")
COMPATIBLE_LANGOPT(ModulesDeclUse , 1, 0, "require declaration of module uses")
BENIGN_LANGOPT(ModulesSearchAll , 1, 1, "searching even non-imported modules to find unresolved references")
COMPATIBLE_LANGOPT(ModulesStrictDeclUse, 1, 0, "requiring declaration of module uses and all headers to be in modules")
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 2910b8521bab..ab296ebb9f6a 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -167,6 +167,9 @@ def disable_llvm_passes : Flag<["-"], "disable-llvm-passes">,
"frontend by not running any LLVM passes at all">;
def disable_llvm_optzns : Flag<["-"], "disable-llvm-optzns">,
Alias<disable_llvm_passes>;
+def disable_lifetimemarkers : Flag<["-"], "disable-lifetime-markers">,
+ HelpText<"Disable lifetime-markers emission even when optimizations are "
+ "enabled">;
def disable_red_zone : Flag<["-"], "disable-red-zone">,
HelpText<"Do not emit code that uses the red zone.">;
def dwarf_column_info : Flag<["-"], "dwarf-column-info">,
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index 54c9f81265a6..964a6cc2a007 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -52,6 +52,7 @@ CODEGENOPT(DisableGCov , 1, 0) ///< Don't run the GCov pass, for testing.
CODEGENOPT(DisableLLVMPasses , 1, 0) ///< Don't run any LLVM IR passes to get
///< the pristine IR generated by the
///< frontend.
+CODEGENOPT(DisableLifetimeMarkers, 1, 0) ///< Don't emit any lifetime markers
CODEGENOPT(ExperimentalNewPassManager, 1, 0) ///< Enables the new, experimental
///< pass manager.
CODEGENOPT(DisableRedZone , 1, 0) ///< Set when -mno-red-zone is enabled.
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index a073ca5bfd2a..20fddc4d5a52 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -88,6 +88,8 @@ public:
static std::unique_ptr<raw_pwrite_stream>
ComputeASTConsumerArguments(CompilerInstance &CI, StringRef InFile,
std::string &Sysroot, std::string &OutputFile);
+
+ bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
};
class GenerateModuleAction : public ASTFrontendAction {
diff --git a/include/clang/Index/IndexSymbol.h b/include/clang/Index/IndexSymbol.h
index cac0b53a939e..559b212b9266 100644
--- a/include/clang/Index/IndexSymbol.h
+++ b/include/clang/Index/IndexSymbol.h
@@ -59,6 +59,13 @@ enum class SymbolLanguage {
CXX,
};
+/// Language specific sub-kinds.
+enum class SymbolSubKind {
+ None,
+ CXXCopyConstructor,
+ CXXMoveConstructor,
+};
+
/// Set of properties that provide additional info about a symbol.
enum class SymbolProperty : uint8_t {
Generic = 1 << 0,
@@ -107,6 +114,7 @@ struct SymbolRelation {
struct SymbolInfo {
SymbolKind Kind;
+ SymbolSubKind SubKind;
SymbolPropertySet Properties;
SymbolLanguage Lang;
};
@@ -121,6 +129,7 @@ void printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS);
bool printSymbolName(const Decl *D, const LangOptions &LO, raw_ostream &OS);
StringRef getSymbolKindString(SymbolKind K);
+StringRef getSymbolSubKindString(SymbolSubKind K);
StringRef getSymbolLanguageString(SymbolLanguage K);
void applyForEachSymbolProperty(SymbolPropertySet Props,
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index a7b8cce32691..94be58ac8aeb 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -215,14 +215,14 @@ public:
/// \brief Create the initialization entity for a parameter.
static InitializedEntity InitializeParameter(ASTContext &Context,
- ParmVarDecl *Parm) {
+ const ParmVarDecl *Parm) {
return InitializeParameter(Context, Parm, Parm->getType());
}
/// \brief Create the initialization entity for a parameter, but use
/// another type.
static InitializedEntity InitializeParameter(ASTContext &Context,
- ParmVarDecl *Parm,
+ const ParmVarDecl *Parm,
QualType Type) {
bool Consumed = (Context.getLangOpts().ObjCAutoRefCount &&
Parm->hasAttr<NSConsumedAttr>());
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 376db92d03bd..88fdc991f394 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -531,6 +531,13 @@ namespace clang {
Ambiguous.construct();
}
+ void setAsIdentityConversion(QualType T) {
+ setStandard();
+ Standard.setAsIdentityConversion();
+ Standard.setFromType(T);
+ Standard.setAllToTypes(T);
+ }
+
/// \brief Whether the target is really a std::initializer_list, and the
/// sequence only represents the worst element conversion.
bool isStdInitializerListElement() const {
@@ -601,8 +608,17 @@ namespace clang {
/// This candidate was not viable because its OpenCL extension is disabled.
ovl_fail_ext_disabled,
+
+ /// This inherited constructor is not viable because it would slice the
+ /// argument.
+ ovl_fail_inhctor_slice,
};
+ /// A list of implicit conversion sequences for the arguments of an
+ /// OverloadCandidate.
+ typedef llvm::MutableArrayRef<ImplicitConversionSequence>
+ ConversionSequenceList;
+
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
struct OverloadCandidate {
/// Function - The actual function that this candidate
@@ -627,18 +643,13 @@ namespace clang {
/// is a surrogate, but only if IsSurrogate is true.
CXXConversionDecl *Surrogate;
- /// Conversions - The conversion sequences used to convert the
- /// function arguments to the function parameters, the pointer points to a
- /// fixed size array with NumConversions elements. The memory is owned by
- /// the OverloadCandidateSet.
- ImplicitConversionSequence *Conversions;
+ /// The conversion sequences used to convert the function arguments
+ /// to the function parameters.
+ ConversionSequenceList Conversions;
/// The FixIt hints which can be used to fix the Bad candidate.
ConversionFixItGenerator Fix;
- /// NumConversions - The number of elements in the Conversions array.
- unsigned NumConversions;
-
/// Viable - True to indicate that this overload candidate is viable.
bool Viable;
@@ -664,6 +675,26 @@ namespace clang {
/// to be used while performing partial ordering of function templates.
unsigned ExplicitCallArguments;
+ /// The number of diagnose_if attributes that this overload triggered.
+ /// If any of the triggered attributes are errors, this won't count
+ /// diagnose_if warnings.
+ unsigned NumTriggeredDiagnoseIfs = 0;
+
+ /// Basically a TinyPtrVector<DiagnoseIfAttr *> that doesn't own the vector:
+ /// If NumTriggeredDiagnoseIfs is 0 or 1, this is a DiagnoseIfAttr *,
+ /// otherwise it's a pointer to an array of `NumTriggeredDiagnoseIfs`
+ /// DiagnoseIfAttr *s.
+ llvm::PointerUnion<DiagnoseIfAttr *, DiagnoseIfAttr **> DiagnoseIfInfo;
+
+ /// Gets an ArrayRef for the data at DiagnoseIfInfo. Note that this may give
+ /// you a pointer into DiagnoseIfInfo.
+ ArrayRef<DiagnoseIfAttr *> getDiagnoseIfInfo() const {
+ auto *Ptr = NumTriggeredDiagnoseIfs <= 1
+ ? DiagnoseIfInfo.getAddrOfPtr1()
+ : DiagnoseIfInfo.get<DiagnoseIfAttr **>();
+ return {Ptr, NumTriggeredDiagnoseIfs};
+ }
+
union {
DeductionFailureInfo DeductionFailure;
@@ -677,9 +708,9 @@ namespace clang {
/// hasAmbiguousConversion - Returns whether this overload
/// candidate requires an ambiguous conversion or not.
bool hasAmbiguousConversion() const {
- for (unsigned i = 0, e = NumConversions; i != e; ++i) {
- if (!Conversions[i].isInitialized()) return false;
- if (Conversions[i].isAmbiguous()) return true;
+ for (auto &C : Conversions) {
+ if (!C.isInitialized()) return false;
+ if (C.isAmbiguous()) return true;
}
return false;
}
@@ -728,17 +759,42 @@ namespace clang {
SmallVector<OverloadCandidate, 16> Candidates;
llvm::SmallPtrSet<Decl *, 16> Functions;
- // Allocator for OverloadCandidate::Conversions. We store the first few
- // elements inline to avoid allocation for small sets.
- llvm::BumpPtrAllocator ConversionSequenceAllocator;
+ // Allocator for ConversionSequenceLists and DiagnoseIfAttr* arrays.
+ // We store the first few of each of these inline to avoid allocation for
+ // small sets.
+ llvm::BumpPtrAllocator SlabAllocator;
SourceLocation Loc;
CandidateSetKind Kind;
- unsigned NumInlineSequences;
- llvm::AlignedCharArray<alignof(ImplicitConversionSequence),
- 16 * sizeof(ImplicitConversionSequence)>
- InlineSpace;
+ constexpr static unsigned NumInlineBytes =
+ 24 * sizeof(ImplicitConversionSequence);
+ unsigned NumInlineBytesUsed;
+ llvm::AlignedCharArray<alignof(void *), NumInlineBytes> InlineSpace;
+
+ /// If we have space, allocates from inline storage. Otherwise, allocates
+ /// from the slab allocator.
+ /// FIXME: It would probably be nice to have a SmallBumpPtrAllocator
+ /// instead.
+ template <typename T>
+ T *slabAllocate(unsigned N) {
+ // It's simpler if this doesn't need to consider alignment.
+ static_assert(alignof(T) == alignof(void *),
+ "Only works for pointer-aligned types.");
+ static_assert(std::is_trivial<T>::value ||
+ std::is_same<ImplicitConversionSequence, T>::value,
+ "Add destruction logic to OverloadCandidateSet::clear().");
+
+ unsigned NBytes = sizeof(T) * N;
+ if (NBytes > NumInlineBytes - NumInlineBytesUsed)
+ return SlabAllocator.Allocate<T>(N);
+ char *FreeSpaceStart = InlineSpace.buffer + NumInlineBytesUsed;
+ assert(uintptr_t(FreeSpaceStart) % alignof(void *) == 0 &&
+ "Misaligned storage!");
+
+ NumInlineBytesUsed += NBytes;
+ return reinterpret_cast<T *>(FreeSpaceStart);
+ }
OverloadCandidateSet(const OverloadCandidateSet &) = delete;
void operator=(const OverloadCandidateSet &) = delete;
@@ -747,12 +803,17 @@ namespace clang {
public:
OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK)
- : Loc(Loc), Kind(CSK), NumInlineSequences(0) {}
+ : Loc(Loc), Kind(CSK), NumInlineBytesUsed(0) {}
~OverloadCandidateSet() { destroyCandidates(); }
SourceLocation getLocation() const { return Loc; }
CandidateSetKind getKind() const { return Kind; }
+ /// Make a DiagnoseIfAttr* array in a block of memory that will live for
+ /// as long as this OverloadCandidateSet. Returns a pointer to the start
+ /// of that array.
+ DiagnoseIfAttr **addDiagnoseIfComplaints(ArrayRef<DiagnoseIfAttr *> CA);
+
/// \brief Determine when this overload candidate will be new to the
/// overload set.
bool isNewCandidate(Decl *F) {
@@ -769,30 +830,32 @@ namespace clang {
size_t size() const { return Candidates.size(); }
bool empty() const { return Candidates.empty(); }
+ /// \brief Allocate storage for conversion sequences for NumConversions
+ /// conversions.
+ ConversionSequenceList
+ allocateConversionSequences(unsigned NumConversions) {
+ ImplicitConversionSequence *Conversions =
+ slabAllocate<ImplicitConversionSequence>(NumConversions);
+
+ // Construct the new objects.
+ for (unsigned I = 0; I != NumConversions; ++I)
+ new (&Conversions[I]) ImplicitConversionSequence();
+
+ return ConversionSequenceList(Conversions, NumConversions);
+ }
+
/// \brief Add a new candidate with NumConversions conversion sequence slots
/// to the overload set.
- OverloadCandidate &addCandidate(unsigned NumConversions = 0) {
+ OverloadCandidate &addCandidate(unsigned NumConversions = 0,
+ ConversionSequenceList Conversions = None) {
+ assert((Conversions.empty() || Conversions.size() == NumConversions) &&
+ "preallocated conversion sequence has wrong length");
+
Candidates.push_back(OverloadCandidate());
OverloadCandidate &C = Candidates.back();
-
- // Assign space from the inline array if there are enough free slots
- // available.
- if (NumConversions + NumInlineSequences <= 16) {
- ImplicitConversionSequence *I =
- (ImplicitConversionSequence *)InlineSpace.buffer;
- C.Conversions = &I[NumInlineSequences];
- NumInlineSequences += NumConversions;
- } else {
- // Otherwise get memory from the allocator.
- C.Conversions = ConversionSequenceAllocator
- .Allocate<ImplicitConversionSequence>(NumConversions);
- }
-
- // Construct the new objects.
- for (unsigned i = 0; i != NumConversions; ++i)
- new (&C.Conversions[i]) ImplicitConversionSequence();
-
- C.NumConversions = NumConversions;
+ C.Conversions = Conversions.empty()
+ ? allocateConversionSequences(NumConversions)
+ : Conversions;
return C;
}
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index ca984a360a60..d5e4b069f8b7 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -27,6 +27,7 @@
#include "clang/AST/NSAPI.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/ExpressionTraits.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Module.h"
@@ -119,6 +120,7 @@ namespace clang {
class FunctionProtoType;
class FunctionTemplateDecl;
class ImplicitConversionSequence;
+ typedef MutableArrayRef<ImplicitConversionSequence> ConversionSequenceList;
class InitListExpr;
class InitializationKind;
class InitializationSequence;
@@ -806,6 +808,12 @@ public:
/// run time.
Unevaluated,
+ /// \brief The current expression occurs within a braced-init-list within
+ /// an unevaluated operand. This is mostly like a regular unevaluated
+ /// context, except that we still instantiate constexpr functions that are
+ /// referenced here so that we can perform narrowing checks correctly.
+ UnevaluatedList,
+
/// \brief The current expression occurs within a discarded statement.
/// This behaves largely similarly to an unevaluated operand in preventing
/// definitions from being required, but not in other ways.
@@ -898,7 +906,8 @@ public:
MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx);
bool isUnevaluated() const {
- return Context == Unevaluated || Context == UnevaluatedAbstract;
+ return Context == Unevaluated || Context == UnevaluatedAbstract ||
+ Context == UnevaluatedList;
}
};
@@ -2510,10 +2519,11 @@ public:
void AddOverloadCandidate(FunctionDecl *Function,
DeclAccessPair FoundDecl,
ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet,
+ OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions = false,
bool PartialOverloading = false,
- bool AllowExplicit = false);
+ bool AllowExplicit = false,
+ ConversionSequenceList EarlyConversions = None);
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
@@ -2523,23 +2533,25 @@ public:
void AddMethodCandidate(DeclAccessPair FoundDecl,
QualType ObjectType,
Expr::Classification ObjectClassification,
- ArrayRef<Expr *> Args,
+ Expr *ThisArg, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversion = false);
void AddMethodCandidate(CXXMethodDecl *Method,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
- ArrayRef<Expr *> Args,
+ Expr *ThisArg, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
- bool PartialOverloading = false);
+ bool PartialOverloading = false,
+ ConversionSequenceList EarlyConversions = None);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
+ Expr *ThisArg,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
@@ -2551,6 +2563,16 @@ public:
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool PartialOverloading = false);
+ bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate,
+ ArrayRef<QualType> ParamTypes,
+ ArrayRef<Expr *> Args,
+ OverloadCandidateSet &CandidateSet,
+ ConversionSequenceList &Conversions,
+ bool SuppressUserConversions,
+ CXXRecordDecl *ActingContext = nullptr,
+ QualType ObjectType = QualType(),
+ Expr::Classification
+ ObjectClassification = {});
void AddConversionCandidate(CXXConversionDecl *Conversion,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
@@ -2603,6 +2625,38 @@ public:
EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
bool MissingImplicitThis = false);
+ /// Check the diagnose_if attributes on the given function. Returns the
+ /// first succesful fatal attribute, or null if calling Function(Args) isn't
+ /// an error.
+ ///
+ /// This only considers ArgDependent DiagnoseIfAttrs.
+ ///
+ /// This will populate Nonfatal with all non-error DiagnoseIfAttrs that
+ /// succeed. If this function returns non-null, the contents of Nonfatal are
+ /// unspecified.
+ DiagnoseIfAttr *
+ checkArgDependentDiagnoseIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
+ SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
+ bool MissingImplicitThis = false,
+ Expr *ThisArg = nullptr);
+
+ /// Check the diagnose_if expressions on the given function. Returns the
+ /// first succesful fatal attribute, or null if using Function isn't
+ /// an error.
+ ///
+ /// This ignores all ArgDependent DiagnoseIfAttrs.
+ ///
+ /// This will populate Nonfatal with all non-error DiagnoseIfAttrs that
+ /// succeed. If this function returns non-null, the contents of Nonfatal are
+ /// unspecified.
+ DiagnoseIfAttr *
+ checkArgIndependentDiagnoseIf(FunctionDecl *Function,
+ SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal);
+
+ /// Emits the diagnostic contained in the given DiagnoseIfAttr at Loc. Also
+ /// emits a note about the location of said attribute.
+ void emitDiagnoseIfDiagnostic(SourceLocation Loc, const DiagnoseIfAttr *DIA);
+
/// Returns whether the given function's address can be taken or not,
/// optionally emitting a diagnostic if the address can't be taken.
///
@@ -3801,6 +3855,9 @@ public:
/// variable will have in the given scope.
QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc);
+ /// Mark all of the declarations referenced within a particular AST node as
+ /// referenced. Used when template instantiation instantiates a non-dependent
+ /// type -- entities referenced by the type are now referenced.
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
void MarkDeclarationsReferencedInExpr(Expr *E,
bool SkipLocalVariables = false);
@@ -6580,6 +6637,8 @@ public:
/// \brief The explicitly-specified template arguments were not valid
/// template arguments for the given template.
TDK_InvalidExplicitArguments,
+ /// \brief Checking non-dependent argument conversions failed.
+ TDK_NonDependentConversionFailure,
/// \brief Deduction failed; that's all we know.
TDK_MiscellaneousDeductionFailure,
/// \brief CUDA Target attributes do not match.
@@ -6618,22 +6677,21 @@ public:
QualType OriginalArgType;
};
- TemplateDeductionResult
- FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned NumExplicitlySpecified,
- FunctionDecl *&Specialization,
- sema::TemplateDeductionInfo &Info,
- SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr,
- bool PartialOverloading = false);
+ TemplateDeductionResult FinishTemplateArgumentDeduction(
+ FunctionTemplateDecl *FunctionTemplate,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ unsigned NumExplicitlySpecified, FunctionDecl *&Specialization,
+ sema::TemplateDeductionInfo &Info,
+ SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr,
+ bool PartialOverloading = false,
+ llvm::function_ref<bool()> CheckNonDependent = []{ return false; });
- TemplateDeductionResult
- DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- TemplateArgumentListInfo *ExplicitTemplateArgs,
- ArrayRef<Expr *> Args,
- FunctionDecl *&Specialization,
- sema::TemplateDeductionInfo &Info,
- bool PartialOverloading = false);
+ TemplateDeductionResult DeduceTemplateArguments(
+ FunctionTemplateDecl *FunctionTemplate,
+ TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
+ FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info,
+ bool PartialOverloading,
+ llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent);
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
@@ -6877,6 +6935,10 @@ public:
/// Specializations whose definitions are currently being instantiated.
llvm::DenseSet<std::pair<Decl *, unsigned>> InstantiatingSpecializations;
+ /// Non-dependent types used in templates that have already been instantiated
+ /// by some template instantiation.
+ llvm::DenseSet<QualType> InstantiatedNonDependentTypes;
+
/// \brief Extra modules inspected when performing a lookup during a template
/// instantiation. Computed lazily.
SmallVector<Module*, 16> ActiveTemplateInstantiationLookupModules;
@@ -10186,6 +10248,22 @@ public:
IsDecltype);
}
+ enum InitListTag { InitList };
+ EnterExpressionEvaluationContext(Sema &Actions, InitListTag,
+ bool ShouldEnter = true)
+ : Actions(Actions), Entered(false) {
+ // In C++11 onwards, narrowing checks are performed on the contents of
+ // braced-init-lists, even when they occur within unevaluated operands.
+ // Therefore we still need to instantiate constexpr functions used in such
+ // a context.
+ if (ShouldEnter && Actions.isUnevaluatedContext() &&
+ Actions.getLangOpts().CPlusPlus11) {
+ Actions.PushExpressionEvaluationContext(Sema::UnevaluatedList, nullptr,
+ false);
+ Entered = true;
+ }
+ }
+
~EnterExpressionEvaluationContext() {
if (Entered)
Actions.PopExpressionEvaluationContext();
diff --git a/include/clang/StaticAnalyzer/Checkers/Checkers.td b/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 2e58debf80fc..69578910499f 100644
--- a/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -278,6 +278,14 @@ def VirtualCallChecker : Checker<"VirtualCall">,
} // end: "optin.cplusplus"
+let ParentPackage = CplusplusAlpha in {
+
+def IteratorPastEndChecker : Checker<"IteratorPastEnd">,
+ HelpText<"Check iterators used past end">,
+ DescFile<"IteratorPastEndChecker.cpp">;
+
+} // end: "alpha.cplusplus"
+
//===----------------------------------------------------------------------===//
// Valist checkers.
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 6dcb705c44d3..fe77c7f6f3bf 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -4543,6 +4543,12 @@ public:
Call.getLValueBase().dyn_cast<const ValueDecl*>());
if (!FD)
return Error(Callee);
+ // Don't call function pointers which have been cast to some other type.
+ // Per DR (no number yet), the caller and callee can differ in noexcept.
+ if (!Info.Ctx.hasSameFunctionTypeIgnoringExceptionSpec(
+ CalleeType->getPointeeType(), FD->getType())) {
+ return Error(E);
+ }
// Overloaded operator calls to member functions are represented as normal
// calls with '*this' as the first argument.
@@ -4558,14 +4564,42 @@ public:
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
+ // being done for the non-static case), since a static member function
+ // doesn't have an implicit argument passed in.
+ const CXXRecordDecl *ClosureClass = MD->getParent();
+ assert(
+ ClosureClass->captures_begin() == ClosureClass->captures_end() &&
+ "Number of captures must be zero for conversion to function-ptr");
+
+ const CXXMethodDecl *LambdaCallOp =
+ ClosureClass->getLambdaCallOperator();
+
+ // Set 'FD', the function that will be called below, to the call
+ // operator. If the closure object represents a generic lambda, find
+ // the corresponding specialization of the call operator.
+
+ if (ClosureClass->isGenericLambda()) {
+ assert(MD->isFunctionTemplateSpecialization() &&
+ "A generic lambda's static-invoker function must be a "
+ "template specialization");
+ const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs();
+ FunctionTemplateDecl *CallOpTemplate =
+ LambdaCallOp->getDescribedFunctionTemplate();
+ void *InsertPos = nullptr;
+ FunctionDecl *CorrespondingCallOpSpecialization =
+ CallOpTemplate->findSpecialization(TAL->asArray(), InsertPos);
+ assert(CorrespondingCallOpSpecialization &&
+ "We must always have a function call operator specialization "
+ "that corresponds to our static invoker specialization");
+ FD = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);
+ } else
+ FD = LambdaCallOp;
}
- // Don't call function pointers which have been cast to some other type.
- // Per DR (no number yet), the caller and callee can differ in noexcept.
- if (!Info.Ctx.hasSameFunctionTypeIgnoringExceptionSpec(
- CalleeType->getPointeeType(), FD->getType())) {
- return Error(E);
- }
+
} else
return Error(E);
@@ -5834,6 +5868,7 @@ namespace {
bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
return VisitCXXConstructExpr(E, E->getType());
}
+ bool VisitLambdaExpr(const LambdaExpr *E);
bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
@@ -6168,6 +6203,21 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
return true;
}
+bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
+ const CXXRecordDecl *ClosureClass = E->getLambdaClass();
+ if (ClosureClass->isInvalidDecl()) return false;
+
+ if (Info.checkingPotentialConstantExpression()) return true;
+ if (E->capture_size()) {
+ Info.FFDiag(E, diag::note_unimplemented_constexpr_lambda_feature_ast)
+ << "can not evaluate lambda expressions with captures";
+ return false;
+ }
+ // FIXME: Implement captures.
+ Result = APValue(APValue::UninitStruct(), /*NumBases*/0, /*NumFields*/0);
+ return true;
+}
+
static bool EvaluateRecord(const Expr *E, const LValue &This,
APValue &Result, EvalInfo &Info) {
assert(E->isRValue() && E->getType()->isRecordType() &&
@@ -6217,6 +6267,9 @@ public:
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E) {
return VisitConstructExpr(E);
}
+ bool VisitLambdaExpr(const LambdaExpr *E) {
+ return VisitConstructExpr(E);
+ }
};
} // end anonymous namespace
@@ -10357,10 +10410,25 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
const FunctionDecl *Callee,
- ArrayRef<const Expr*> Args) const {
+ ArrayRef<const Expr*> Args,
+ const Expr *This) const {
Expr::EvalStatus Status;
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpressionUnevaluated);
+ LValue ThisVal;
+ const LValue *ThisPtr = nullptr;
+ if (This) {
+#ifndef NDEBUG
+ auto *MD = dyn_cast<CXXMethodDecl>(Callee);
+ assert(MD && "Don't provide `this` for non-methods.");
+ assert(!MD->isStatic() && "Don't provide `this` for static methods.");
+#endif
+ if (EvaluateObjectArgument(Info, This, ThisVal))
+ ThisPtr = &ThisVal;
+ if (Info.EvalStatus.HasSideEffects)
+ return false;
+ }
+
ArgVector ArgValues(Args.size());
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
@@ -10373,7 +10441,7 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
}
// Build fake call to Callee.
- CallStackFrame Frame(Info, Callee->getLocation(), Callee, /*This*/nullptr,
+ CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr,
ArgValues.data());
return Evaluate(Value, Info, this) && !Info.EvalStatus.HasSideEffects;
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 911b8b471a05..76c368d7f04c 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -109,13 +109,13 @@ static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
static const FunctionDecl *getStructor(const NamedDecl *ND) {
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(ND))
- return FTD->getTemplatedDecl();
+ return FTD->getTemplatedDecl()->getCanonicalDecl();
const auto *FD = cast<FunctionDecl>(ND);
if (const auto *FTD = FD->getPrimaryTemplate())
- return FTD->getTemplatedDecl();
+ return FTD->getTemplatedDecl()->getCanonicalDecl();
- return FD;
+ return FD->getCanonicalDecl();
}
/// MicrosoftMangleContextImpl - Overrides the default MangleContext for the
@@ -312,6 +312,10 @@ public:
void mangleNestedName(const NamedDecl *ND);
private:
+ bool isStructorDecl(const NamedDecl *ND) const {
+ return ND == Structor || getStructor(ND) == Structor;
+ }
+
void mangleUnqualifiedName(const NamedDecl *ND) {
mangleUnqualifiedName(ND, ND->getDeclName());
}
@@ -898,7 +902,7 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
llvm_unreachable("Can't mangle Objective-C selector names here!");
case DeclarationName::CXXConstructorName:
- if (Structor == getStructor(ND)) {
+ if (isStructorDecl(ND)) {
if (StructorType == Ctor_CopyingClosure) {
Out << "?_O";
return;
@@ -912,7 +916,7 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
return;
case DeclarationName::CXXDestructorName:
- if (ND == Structor)
+ if (isStructorDecl(ND))
// If the named decl is the C++ destructor we're mangling,
// use the type we were given.
mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
@@ -1862,7 +1866,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
IsStructor = true;
IsCtorClosure = (StructorType == Ctor_CopyingClosure ||
StructorType == Ctor_DefaultClosure) &&
- getStructor(MD) == Structor;
+ isStructorDecl(MD);
if (IsCtorClosure)
CC = getASTContext().getDefaultCallingConvention(
/*IsVariadic=*/false, /*IsCXXMethod=*/true);
@@ -1883,7 +1887,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
// <return-type> ::= <type>
// ::= @ # structors (they have no declared return type)
if (IsStructor) {
- if (isa<CXXDestructorDecl>(D) && D == Structor &&
+ if (isa<CXXDestructorDecl>(D) && isStructorDecl(D) &&
StructorType == Dtor_Deleting) {
// The scalar deleting destructor takes an extra int argument.
// However, the FunctionType generated has 0 arguments.
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index ed09f3a45566..d2ce6ea48e41 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -312,7 +312,8 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
// At O0 and O1 we only run the always inliner which is more efficient. At
// higher optimization levels we run the normal inliner.
if (CodeGenOpts.OptimizationLevel <= 1) {
- bool InsertLifetimeIntrinsics = CodeGenOpts.OptimizationLevel != 0;
+ bool InsertLifetimeIntrinsics = (CodeGenOpts.OptimizationLevel != 0 &&
+ !CodeGenOpts.DisableLifetimeMarkers);
PMBuilder.Inliner = createAlwaysInlinerLegacyPass(InsertLifetimeIntrinsics);
} else {
PMBuilder.Inliner = createFunctionInliningPass(
@@ -519,11 +520,22 @@ void EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
.Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC);
assert(RM.hasValue() && "invalid PIC model!");
- CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
+ CodeGenOpt::Level OptLevel;
switch (CodeGenOpts.OptimizationLevel) {
- default: break;
- case 0: OptLevel = CodeGenOpt::None; break;
- case 3: OptLevel = CodeGenOpt::Aggressive; break;
+ default:
+ llvm_unreachable("Invalid optimization level!");
+ case 0:
+ OptLevel = CodeGenOpt::None;
+ break;
+ case 1:
+ OptLevel = CodeGenOpt::Less;
+ break;
+ case 2:
+ OptLevel = CodeGenOpt::Default;
+ break; // O2/Os/Oz
+ case 3:
+ OptLevel = CodeGenOpt::Aggressive;
+ break;
}
llvm::TargetOptions Options;
@@ -849,21 +861,8 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
}
}
-static void runThinLTOBackend(const CodeGenOptions &CGOpts, Module *M,
+static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M,
std::unique_ptr<raw_pwrite_stream> OS) {
- // If we are performing a ThinLTO importing compile, load the function index
- // into memory and pass it into thinBackend, which will run the function
- // importer and invoke LTO passes.
- Expected<std::unique_ptr<ModuleSummaryIndex>> IndexOrErr =
- llvm::getModuleSummaryIndexForFile(CGOpts.ThinLTOIndexFile);
- if (!IndexOrErr) {
- logAllUnhandledErrors(IndexOrErr.takeError(), errs(),
- "Error loading index file '" +
- CGOpts.ThinLTOIndexFile + "': ");
- return;
- }
- std::unique_ptr<ModuleSummaryIndex> CombinedIndex = std::move(*IndexOrErr);
-
StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
ModuleToDefinedGVSummaries;
CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
@@ -949,8 +948,26 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
BackendAction Action,
std::unique_ptr<raw_pwrite_stream> OS) {
if (!CGOpts.ThinLTOIndexFile.empty()) {
- runThinLTOBackend(CGOpts, M, std::move(OS));
- return;
+ // If we are performing a ThinLTO importing compile, load the function index
+ // into memory and pass it into runThinLTOBackend, which will run the
+ // function importer and invoke LTO passes.
+ Expected<std::unique_ptr<ModuleSummaryIndex>> IndexOrErr =
+ llvm::getModuleSummaryIndexForFile(CGOpts.ThinLTOIndexFile);
+ if (!IndexOrErr) {
+ logAllUnhandledErrors(IndexOrErr.takeError(), errs(),
+ "Error loading index file '" +
+ CGOpts.ThinLTOIndexFile + "': ");
+ return;
+ }
+ std::unique_ptr<ModuleSummaryIndex> CombinedIndex = std::move(*IndexOrErr);
+ // A null CombinedIndex means we should skip ThinLTO compilation
+ // (LLVM will optionally ignore empty index files, returning null instead
+ // of an error).
+ bool DoThinLTOBackend = CombinedIndex != nullptr;
+ if (DoThinLTOBackend) {
+ runThinLTOBackend(CombinedIndex.get(), M, std::move(OS));
+ return;
+ }
}
EmitAssemblyHelper AsmHelper(Diags, HeaderOpts, CGOpts, TOpts, LOpts, M);
diff --git a/lib/CodeGen/CGCleanup.h b/lib/CodeGen/CGCleanup.h
index 2166490ec1fd..105c5629d50c 100644
--- a/lib/CodeGen/CGCleanup.h
+++ b/lib/CodeGen/CGCleanup.h
@@ -616,6 +616,8 @@ struct EHPersonality {
static const EHPersonality GNU_C_SJLJ;
static const EHPersonality GNU_C_SEH;
static const EHPersonality GNU_ObjC;
+ static const EHPersonality GNU_ObjC_SJLJ;
+ static const EHPersonality GNU_ObjC_SEH;
static const EHPersonality GNUstep_ObjC;
static const EHPersonality GNU_ObjCXX;
static const EHPersonality NeXT_ObjC;
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 7b7880e07a95..f908bf2b3b0a 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -97,6 +97,10 @@ EHPersonality::GNU_CPlusPlus_SEH = { "__gxx_personality_seh0", nullptr };
const EHPersonality
EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", "objc_exception_throw"};
const EHPersonality
+EHPersonality::GNU_ObjC_SJLJ = {"__gnu_objc_personality_sj0", "objc_exception_throw"};
+const EHPersonality
+EHPersonality::GNU_ObjC_SEH = {"__gnu_objc_personality_seh0", "objc_exception_throw"};
+const EHPersonality
EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", nullptr };
const EHPersonality
EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", nullptr };
@@ -137,6 +141,10 @@ static const EHPersonality &getObjCPersonality(const llvm::Triple &T,
// fallthrough
case ObjCRuntime::GCC:
case ObjCRuntime::ObjFW:
+ if (L.SjLjExceptions)
+ return EHPersonality::GNU_ObjC_SJLJ;
+ else if (useLibGCCSEHPersonality(T))
+ return EHPersonality::GNU_ObjC_SEH;
return EHPersonality::GNU_ObjC;
}
llvm_unreachable("bad runtime kind");
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 7cab13de923b..137c69420ddf 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -42,6 +42,9 @@ using namespace CodeGen;
/// markers.
static bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts,
const LangOptions &LangOpts) {
+ if (CGOpts.DisableLifetimeMarkers)
+ return false;
+
// Asan uses markers for use-after-scope checks.
if (CGOpts.SanitizeAddressUseAfterScope)
return true;
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 789a2f0525be..547e660ae09b 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -3812,6 +3812,7 @@ ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const {
if (Major >= 7 || Major == 0) {
switch (getArch()) {
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 8e02d45fcc4a..e267cdb2649f 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -9644,6 +9644,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Major >= 7 || Major == 0) {
switch (getToolChain().getArch()) {
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index cf6373f45657..b5f7de280acd 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -1282,9 +1282,7 @@ private:
return TT_UnaryOperator;
const FormatToken *NextToken = Tok.getNextNonComment();
- if (!NextToken ||
- NextToken->isOneOf(tok::arrow, Keywords.kw_final, tok::equal,
- Keywords.kw_override) ||
+ if (!NextToken || NextToken->isOneOf(tok::arrow, tok::equal) ||
(NextToken->is(tok::l_brace) && !NextToken->getNextNonComment()))
return TT_PointerOrReference;
@@ -2088,9 +2086,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
!Line.IsMultiVariableDeclStmt)))
return true;
if (Left.is(TT_PointerOrReference))
- return Right.Tok.isLiteral() ||
- Right.isOneOf(TT_BlockComment, Keywords.kw_final,
- Keywords.kw_override) ||
+ return Right.Tok.isLiteral() || Right.is(TT_BlockComment) ||
+ (Right.isOneOf(Keywords.kw_override, Keywords.kw_final) &&
+ !Right.is(TT_StartOfName)) ||
(Right.is(tok::l_brace) && Right.BlockKind == BK_Block) ||
(!Right.isOneOf(TT_PointerOrReference, TT_ArraySubscriptLSquare,
tok::l_paren) &&
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 370cf7afa330..8fc3b78aee01 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -737,7 +737,7 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() {
return;
}
if (Next->is(tok::exclaim) && PreviousMustBeValue)
- addUnwrappedLine();
+ return addUnwrappedLine();
bool NextMustBeValue = mustBeJSIdentOrValue(Keywords, Next);
bool NextEndsTemplateExpr =
Next->is(TT_TemplateString) && Next->TokenText.startswith("}");
@@ -745,9 +745,10 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() {
(PreviousMustBeValue ||
Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus,
tok::minusminus)))
- addUnwrappedLine();
- if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next))
- addUnwrappedLine();
+ return addUnwrappedLine();
+ if ((PreviousMustBeValue || Previous->is(tok::r_brace)) &&
+ isJSDeclOrStmt(Keywords, Next))
+ return addUnwrappedLine();
}
void UnwrappedLineParser::parseStructuralElement() {
@@ -1974,7 +1975,14 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() {
!FormatTok->isStringLiteral())
return;
- while (!eof() && FormatTok->isNot(tok::semi)) {
+ while (!eof()) {
+ if (FormatTok->is(tok::semi))
+ return;
+ if (Line->Tokens.size() == 0) {
+ // Common issue: Automatic Semicolon Insertion wrapped the line, so the
+ // import statement should terminate.
+ return;
+ }
if (FormatTok->is(tok::l_brace)) {
FormatTok->BlockKind = BK_Block;
parseBracedList();
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 93bbcc42da1a..36f6b0a5111a 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -520,6 +520,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.EmitLLVMUseLists = A->getOption().getID() == OPT_emit_llvm_uselists;
Opts.DisableLLVMPasses = Args.hasArg(OPT_disable_llvm_passes);
+ Opts.DisableLifetimeMarkers = Args.hasArg(OPT_disable_lifetimemarkers);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables);
Opts.UseRegisterSizedBitfieldAccess = Args.hasArg(
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index eb91940cbbfc..f795a1d0475a 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -127,6 +127,12 @@ GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
return OS;
}
+bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI,
+ StringRef Filename) {
+ CI.getLangOpts().CompilingPCH = true;
+ return true;
+}
+
std::unique_ptr<ASTConsumer>
GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp
index b2342453a916..be847e762091 100644
--- a/lib/Index/IndexSymbol.cpp
+++ b/lib/Index/IndexSymbol.cpp
@@ -53,6 +53,7 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
assert(D);
SymbolInfo Info;
Info.Kind = SymbolKind::Unknown;
+ Info.SubKind = SymbolSubKind::None;
Info.Properties = SymbolPropertySet();
Info.Lang = SymbolLanguage::C;
@@ -183,10 +184,16 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
Info.Kind = SymbolKind::NamespaceAlias;
Info.Lang = SymbolLanguage::CXX;
break;
- case Decl::CXXConstructor:
+ case Decl::CXXConstructor: {
Info.Kind = SymbolKind::Constructor;
Info.Lang = SymbolLanguage::CXX;
+ auto *CD = cast<CXXConstructorDecl>(D);
+ if (CD->isCopyConstructor())
+ Info.SubKind = SymbolSubKind::CXXCopyConstructor;
+ else if (CD->isMoveConstructor())
+ Info.SubKind = SymbolSubKind::CXXMoveConstructor;
break;
+ }
case Decl::CXXDestructor:
Info.Kind = SymbolKind::Destructor;
Info.Lang = SymbolLanguage::CXX;
@@ -363,6 +370,15 @@ StringRef index::getSymbolKindString(SymbolKind K) {
llvm_unreachable("invalid symbol kind");
}
+StringRef index::getSymbolSubKindString(SymbolSubKind K) {
+ switch (K) {
+ case SymbolSubKind::None: return "<none>";
+ case SymbolSubKind::CXXCopyConstructor: return "cxx-copy-ctor";
+ case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor";
+ }
+ llvm_unreachable("invalid symbol subkind");
+}
+
StringRef index::getSymbolLanguageString(SymbolLanguage K) {
switch (K) {
case SymbolLanguage::C: return "C";
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 85504de3d15d..9661e7b13f72 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1996,10 +1996,12 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// Ask HeaderInfo if we should enter this #include file. If not, #including
// this file will have no effect.
+ bool SkipHeader = false;
if (ShouldEnter &&
!HeaderInfo.ShouldEnterIncludeFile(*this, File, isImport,
SuggestedModule.getModule())) {
ShouldEnter = false;
+ SkipHeader = true;
if (Callbacks)
Callbacks->FileSkipped(*File, FilenameTok, FileCharacter);
}
@@ -2008,6 +2010,14 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
if (!ShouldEnter) {
// If this is a module import, make it visible if needed.
if (auto *M = SuggestedModule.getModule()) {
+ // When building a pch, -fmodule-name tells the compiler to textually
+ // include headers in the specified module. But it is possible that
+ // ShouldEnter is false because we are skipping the header. In that
+ // case, We are not importing the specified module.
+ if (SkipHeader && getLangOpts().CompilingPCH &&
+ M->getTopLevelModuleName() == getLangOpts().CurrentModule)
+ return;
+
makeModuleVisible(M, HashLoc);
if (IncludeTok.getIdentifierInfo()->getPPKeywordID() !=
@@ -2032,6 +2042,13 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// Determine if we're switching to building a new submodule, and which one.
if (auto *M = SuggestedModule.getModule()) {
+ // When building a pch, -fmodule-name tells the compiler to textually
+ // include headers in the specified module. We are not building the
+ // specified module.
+ if (getLangOpts().CompilingPCH &&
+ M->getTopLevelModuleName() == getLangOpts().CurrentModule)
+ return;
+
assert(!CurSubmodule && "should not have marked this as a module yet");
CurSubmodule = M;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index ba24adefe6b0..833d93e4548a 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -306,10 +306,11 @@ unsigned Parser::ParseAttributeArgsCommon(
// Parse the non-empty comma-separated list of expressions.
do {
- bool ShouldEnter = attributeParsedArgsUnevaluated(*AttrName);
+ bool Uneval = attributeParsedArgsUnevaluated(*AttrName);
EnterExpressionEvaluationContext Unevaluated(
- Actions, Sema::Unevaluated, /*LambdaContextDecl=*/nullptr,
- /*IsDecltype=*/false, ShouldEnter);
+ Actions, Uneval ? Sema::Unevaluated : Sema::ConstantEvaluated,
+ /*LambdaContextDecl=*/nullptr,
+ /*IsDecltype=*/false);
ExprResult ArgExpr(
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 4a68942f6d2c..fa6b75daed92 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -404,6 +404,10 @@ ExprResult Parser::ParseBraceInitializer() {
return Actions.ActOnInitList(LBraceLoc, None, ConsumeBrace());
}
+ // Enter an appropriate expression evaluation context for an initializer list.
+ EnterExpressionEvaluationContext EnterContext(
+ Actions, EnterExpressionEvaluationContext::InitList);
+
bool InitExprsOk = true;
while (1) {
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 9c902959233f..49208e20a49d 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -1242,7 +1242,8 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
QualType RHSTy = RHS.get()->getType();
llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch();
- bool IsPolyUnsigned = Arch == llvm::Triple::aarch64;
+ bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 ||
+ Arch == llvm::Triple::aarch64_be;
bool IsInt64Long =
Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong;
QualType EltTy =
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index f9b6a91a300f..c6a5bc74145c 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -32,6 +32,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MathExtras.h"
@@ -890,34 +891,117 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- S.Diag(Attr.getLoc(), diag::ext_clang_enable_if);
-
- Expr *Cond = Attr.getArgAsExpr(0);
+static bool checkFunctionConditionAttr(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ Expr *&Cond, StringRef &Msg) {
+ Cond = Attr.getArgAsExpr(0);
if (!Cond->isTypeDependent()) {
ExprResult Converted = S.PerformContextuallyConvertToBool(Cond);
if (Converted.isInvalid())
- return;
+ return false;
Cond = Converted.get();
}
- StringRef Msg;
if (!S.checkStringLiteralArgumentAttr(Attr, 1, Msg))
- return;
+ return false;
+
+ if (Msg.empty())
+ Msg = "<no message provided>";
SmallVector<PartialDiagnosticAt, 8> Diags;
if (!Cond->isValueDependent() &&
!Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D),
Diags)) {
- S.Diag(Attr.getLoc(), diag::err_enable_if_never_constant_expr);
+ S.Diag(Attr.getLoc(), diag::err_attr_cond_never_constant_expr)
+ << Attr.getName();
for (const PartialDiagnosticAt &PDiag : Diags)
S.Diag(PDiag.first, PDiag.second);
+ return false;
+ }
+ return true;
+}
+
+static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ S.Diag(Attr.getLoc(), diag::ext_clang_enable_if);
+
+ Expr *Cond;
+ StringRef Msg;
+ if (checkFunctionConditionAttr(S, D, Attr, Cond, Msg))
+ D->addAttr(::new (S.Context)
+ EnableIfAttr(Attr.getRange(), S.Context, Cond, Msg,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+namespace {
+/// Determines if a given Expr references any of the given function's
+/// ParmVarDecls, or the function's implicit `this` parameter (if applicable).
+class ArgumentDependenceChecker
+ : public RecursiveASTVisitor<ArgumentDependenceChecker> {
+#ifndef NDEBUG
+ const CXXRecordDecl *ClassType;
+#endif
+ llvm::SmallPtrSet<const ParmVarDecl *, 16> Parms;
+ bool Result;
+
+public:
+ ArgumentDependenceChecker(const FunctionDecl *FD) {
+#ifndef NDEBUG
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
+ ClassType = MD->getParent();
+ else
+ ClassType = nullptr;
+#endif
+ Parms.insert(FD->param_begin(), FD->param_end());
+ }
+
+ bool referencesArgs(Expr *E) {
+ Result = false;
+ TraverseStmt(E);
+ return Result;
+ }
+
+ bool VisitCXXThisExpr(CXXThisExpr *E) {
+ assert(E->getType()->getPointeeCXXRecordDecl() == ClassType &&
+ "`this` doesn't refer to the enclosing class?");
+ Result = true;
+ return false;
+ }
+
+ bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+ if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
+ if (Parms.count(PVD)) {
+ Result = true;
+ return false;
+ }
+ return true;
+ }
+};
+}
+
+static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ S.Diag(Attr.getLoc(), diag::ext_clang_diagnose_if);
+
+ Expr *Cond;
+ StringRef Msg;
+ if (!checkFunctionConditionAttr(S, D, Attr, Cond, Msg))
+ return;
+
+ StringRef DiagTypeStr;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 2, DiagTypeStr))
+ return;
+
+ DiagnoseIfAttr::DiagnosticType DiagType;
+ if (!DiagnoseIfAttr::ConvertStrToDiagnosticType(DiagTypeStr, DiagType)) {
+ S.Diag(Attr.getArgAsExpr(2)->getLocStart(),
+ diag::err_diagnose_if_invalid_diagnostic_type);
return;
}
- D->addAttr(::new (S.Context)
- EnableIfAttr(Attr.getRange(), S.Context, Cond, Msg,
- Attr.getAttributeSpellingListIndex()));
+ auto *FD = cast<FunctionDecl>(D);
+ bool ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
+ D->addAttr(::new (S.Context) DiagnoseIfAttr(
+ Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, FD,
+ Attr.getAttributeSpellingListIndex()));
}
static void handlePassObjectSizeAttr(Sema &S, Decl *D,
@@ -5682,6 +5766,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_EnableIf:
handleEnableIfAttr(S, D, Attr);
break;
+ case AttributeList::AT_DiagnoseIf:
+ handleDiagnoseIfAttr(S, D, Attr);
+ break;
case AttributeList::AT_ExtVectorType:
handleExtVectorTypeAttr(S, scope, D, Attr);
break;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index a650621b573a..a70e16cce18c 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -5395,14 +5395,32 @@ static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) {
}
}
-static void checkForMultipleExportedDefaultConstructors(Sema &S, CXXRecordDecl *Class) {
+static void checkForMultipleExportedDefaultConstructors(Sema &S,
+ CXXRecordDecl *Class) {
+ // Only the MS ABI has default constructor closures, so we don't need to do
+ // this semantic checking anywhere else.
+ if (!S.Context.getTargetInfo().getCXXABI().isMicrosoft())
+ return;
+
CXXConstructorDecl *LastExportedDefaultCtor = nullptr;
for (Decl *Member : Class->decls()) {
// Look for exported default constructors.
auto *CD = dyn_cast<CXXConstructorDecl>(Member);
- if (!CD || !CD->isDefaultConstructor() || !CD->hasAttr<DLLExportAttr>())
+ if (!CD || !CD->isDefaultConstructor())
+ continue;
+ auto *Attr = CD->getAttr<DLLExportAttr>();
+ if (!Attr)
continue;
+ // If the class is non-dependent, mark the default arguments as ODR-used so
+ // that we can properly codegen the constructor closure.
+ if (!Class->isDependentContext()) {
+ for (ParmVarDecl *PD : CD->parameters()) {
+ (void)S.CheckCXXDefaultArgExpr(Attr->getLocation(), CD, PD);
+ S.DiscardCleanupsInEvaluationContext();
+ }
+ }
+
if (LastExportedDefaultCtor) {
S.Diag(LastExportedDefaultCtor->getLocation(),
diag::err_attribute_dll_ambiguous_default_ctor)
@@ -9135,6 +9153,16 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// invalid).
if (R.empty() &&
NameInfo.getName().getNameKind() != DeclarationName::CXXConstructorName) {
+ // HACK: Work around a bug in libstdc++'s detection of ::gets. Sometimes
+ // it will believe that glibc provides a ::gets in cases where it does not,
+ // and will try to pull it into namespace std with a using-declaration.
+ // Just ignore the using-declaration in that case.
+ auto *II = NameInfo.getName().getAsIdentifierInfo();
+ if (getLangOpts().CPlusPlus14 && II && II->isStr("gets") &&
+ CurContext->isStdNamespace() &&
+ isa<TranslationUnitDecl>(LookupContext) &&
+ getSourceManager().isInSystemHeader(UsingLoc))
+ return nullptr;
if (TypoCorrection Corrected = CorrectTypo(
R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
llvm::make_unique<UsingValidatorCCC>(
@@ -9828,9 +9856,14 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
}
// Field constructors.
- for (const auto *F : ClassDecl->fields()) {
+ for (auto *F : ClassDecl->fields()) {
if (F->hasInClassInitializer()) {
- if (Expr *E = F->getInClassInitializer())
+ Expr *E = F->getInClassInitializer();
+ if (!E)
+ // FIXME: It's a little wasteful to build and throw away a
+ // CXXDefaultInitExpr here.
+ E = BuildCXXDefaultInitExpr(Loc, F).get();
+ if (E)
ExceptSpec.CalledExpr(E);
} else if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
@@ -12291,6 +12324,10 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
if (Field->getInClassInitializer())
return CXXDefaultInitExpr::Create(Context, Loc, Field);
+ // If we might have already tried and failed to instantiate, don't try again.
+ if (Field->isInvalidDecl())
+ return ExprError();
+
// Maybe we haven't instantiated the in-class initializer. Go check the
// pattern FieldDecl to see if it has one.
CXXRecordDecl *ParentRD = cast<CXXRecordDecl>(Field->getParent());
@@ -12320,8 +12357,11 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
}
if (InstantiateInClassInitializer(Loc, Field, Pattern,
- getTemplateInstantiationArgs(Field)))
+ getTemplateInstantiationArgs(Field))) {
+ // Don't diagnose this again.
+ Field->setInvalidDecl();
return ExprError();
+ }
return CXXDefaultInitExpr::Create(Context, Loc, Field);
}
@@ -12344,6 +12384,8 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
<< OutermostClass << Field;
Diag(Field->getLocEnd(), diag::note_in_class_initializer_not_yet_parsed);
+ // Don't diagnose this again.
+ Field->setInvalidDecl();
return ExprError();
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 1509b22a9e5a..d62e8fd68b64 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -342,6 +342,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
}
// See if this is a deleted function.
+ SmallVector<DiagnoseIfAttr *, 4> DiagnoseIfWarnings;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isDeleted()) {
auto *Ctor = dyn_cast<CXXConstructorDecl>(FD);
@@ -363,6 +364,12 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD))
return true;
+
+ if (const DiagnoseIfAttr *A =
+ checkArgIndependentDiagnoseIf(FD, DiagnoseIfWarnings)) {
+ emitDiagnoseIfDiagnostic(Loc, A);
+ return true;
+ }
}
// [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
@@ -377,6 +384,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
Diag(D->getLocation(), diag::note_entity_declared_at) << D;
return true;
}
+
+ for (const auto *W : DiagnoseIfWarnings)
+ emitDiagnoseIfDiagnostic(Loc, W);
+
DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass,
ObjCPropertyAccess);
@@ -5154,12 +5165,40 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
return OverloadDecl;
}
-static bool isNumberOfArgsValidForCall(Sema &S, const FunctionDecl *Callee,
- std::size_t NumArgs) {
- if (S.TooManyArguments(Callee->getNumParams(), NumArgs,
- /*PartialOverloading=*/false))
- return Callee->isVariadic();
- return Callee->getMinRequiredArguments() <= NumArgs;
+static void checkDirectCallValidity(Sema &S, const Expr *Fn,
+ FunctionDecl *Callee,
+ MultiExprArg ArgExprs) {
+ // `Callee` (when called with ArgExprs) may be ill-formed. enable_if (and
+ // similar attributes) really don't like it when functions are called with an
+ // invalid number of args.
+ if (S.TooManyArguments(Callee->getNumParams(), ArgExprs.size(),
+ /*PartialOverloading=*/false) &&
+ !Callee->isVariadic())
+ return;
+ if (Callee->getMinRequiredArguments() > ArgExprs.size())
+ return;
+
+ if (const EnableIfAttr *Attr = S.CheckEnableIf(Callee, ArgExprs, true)) {
+ S.Diag(Fn->getLocStart(),
+ isa<CXXMethodDecl>(Callee)
+ ? diag::err_ovl_no_viable_member_function_in_call
+ : diag::err_ovl_no_viable_function_in_call)
+ << Callee << Callee->getSourceRange();
+ S.Diag(Callee->getLocation(),
+ diag::note_ovl_candidate_disabled_by_function_cond_attr)
+ << Attr->getCond()->getSourceRange() << Attr->getMessage();
+ return;
+ }
+
+ SmallVector<DiagnoseIfAttr *, 4> Nonfatal;
+ if (const DiagnoseIfAttr *Attr = S.checkArgDependentDiagnoseIf(
+ Callee, ArgExprs, Nonfatal, /*MissingImplicitThis=*/true)) {
+ S.emitDiagnoseIfDiagnostic(Fn->getLocStart(), Attr);
+ return;
+ }
+
+ for (const auto *W : Nonfatal)
+ S.emitDiagnoseIfDiagnostic(Fn->getLocStart(), W);
}
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
@@ -5294,26 +5333,8 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
if (getLangOpts().OpenCL && checkOpenCLDisabledDecl(*FD, *Fn))
return ExprError();
-
- // CheckEnableIf assumes that the we're passing in a sane number of args for
- // FD, but that doesn't always hold true here. This is because, in some
- // cases, we'll emit a diag about an ill-formed function call, but then
- // we'll continue on as if the function call wasn't ill-formed. So, if the
- // number of args looks incorrect, don't do enable_if checks; we should've
- // already emitted an error about the bad call.
- if (FD->hasAttr<EnableIfAttr>() &&
- isNumberOfArgsValidForCall(*this, FD, ArgExprs.size())) {
- if (const EnableIfAttr *Attr = CheckEnableIf(FD, ArgExprs, true)) {
- Diag(Fn->getLocStart(),
- isa<CXXMethodDecl>(FD)
- ? diag::err_ovl_no_viable_member_function_in_call
- : diag::err_ovl_no_viable_function_in_call)
- << FD << FD->getSourceRange();
- Diag(FD->getLocation(),
- diag::note_ovl_candidate_disabled_by_enable_if_attr)
- << Attr->getCond()->getSourceRange() << Attr->getMessage();
- }
- }
+
+ checkDirectCallValidity(*this, Fn, FD, ArgExprs);
}
return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
@@ -13097,8 +13118,16 @@ void Sema::PopExpressionEvaluationContext() {
// evaluate [...] a lambda-expression.
D = diag::err_lambda_in_constant_expression;
}
- for (const auto *L : Rec.Lambdas)
- Diag(L->getLocStart(), D);
+
+ // C++1z allows lambda expressions as core constant expressions.
+ // FIXME: In C++1z, reinstate the restrictions on lambda expressions (CWG
+ // 1607) from appearing within template-arguments and array-bounds that
+ // are part of function-signatures. Be mindful that P0315 (Lambdas in
+ // unevaluated contexts) might lift some of these restrictions in a
+ // future version.
+ if (Rec.Context != ConstantEvaluated || !getLangOpts().CPlusPlus1z)
+ for (const auto *L : Rec.Lambdas)
+ Diag(L->getLocStart(), D);
} else {
// Mark the capture expressions odr-used. This was deferred
// during lambda expression creation.
@@ -13150,41 +13179,63 @@ ExprResult Sema::HandleExprEvaluationContextForTypeof(Expr *E) {
return TransformToPotentiallyEvaluated(E);
}
-static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) {
- // Do not mark anything as "used" within a dependent context; wait for
- // an instantiation.
- if (SemaRef.CurContext->isDependentContext())
- return false;
-
+/// Are we within a context in which some evaluation could be performed (be it
+/// constant evaluation or runtime evaluation)? Sadly, this notion is not quite
+/// captured by C++'s idea of an "unevaluated context".
+static bool isEvaluatableContext(Sema &SemaRef) {
switch (SemaRef.ExprEvalContexts.back().Context) {
case Sema::Unevaluated:
case Sema::UnevaluatedAbstract:
- // We are in an expression that is not potentially evaluated; do nothing.
- // (Depending on how you read the standard, we actually do need to do
- // something here for null pointer constants, but the standard's
- // definition of a null pointer constant is completely crazy.)
+ case Sema::DiscardedStatement:
+ // Expressions in this context are never evaluated.
+ return false;
+
+ case Sema::UnevaluatedList:
+ case Sema::ConstantEvaluated:
+ case Sema::PotentiallyEvaluated:
+ // Expressions in this context could be evaluated.
+ return true;
+
+ case Sema::PotentiallyEvaluatedIfUsed:
+ // Referenced declarations will only be used if the construct in the
+ // containing expression is used, at which point we'll be given another
+ // turn to mark them.
return false;
+ }
+ llvm_unreachable("Invalid context");
+}
+/// Are we within a context in which references to resolved functions or to
+/// variables result in odr-use?
+static bool isOdrUseContext(Sema &SemaRef, bool SkipDependentUses = true) {
+ // An expression in a template is not really an expression until it's been
+ // instantiated, so it doesn't trigger odr-use.
+ if (SkipDependentUses && SemaRef.CurContext->isDependentContext())
+ return false;
+
+ switch (SemaRef.ExprEvalContexts.back().Context) {
+ case Sema::Unevaluated:
+ case Sema::UnevaluatedList:
+ case Sema::UnevaluatedAbstract:
case Sema::DiscardedStatement:
- // These are technically a potentially evaluated but they have the effect
- // of suppressing use marking.
return false;
case Sema::ConstantEvaluated:
case Sema::PotentiallyEvaluated:
- // We are in a potentially evaluated expression (or a constant-expression
- // in C++03); we need to do implicit template instantiation, implicitly
- // define class members, and mark most declarations as used.
return true;
case Sema::PotentiallyEvaluatedIfUsed:
- // Referenced declarations will only be used if the construct in the
- // containing expression is used.
return false;
}
llvm_unreachable("Invalid context");
}
+static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) {
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func);
+ return Func->isConstexpr() &&
+ (Func->isImplicitlyInstantiable() || (MD && !MD->isUserProvided()));
+}
+
/// \brief Mark a function referenced, and check whether it is odr-used
/// (C++ [basic.def.odr]p2, C99 6.9p3)
void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
@@ -13200,7 +13251,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
//
// We (incorrectly) mark overload resolution as an unevaluated context, so we
// can just check that here.
- bool OdrUse = MightBeOdrUse && IsPotentiallyEvaluatedContext(*this);
+ bool OdrUse = MightBeOdrUse && isOdrUseContext(*this);
// Determine whether we require a function definition to exist, per
// C++11 [temp.inst]p3:
@@ -13209,27 +13260,11 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// specialization is implicitly instantiated when the specialization is
// referenced in a context that requires a function definition to exist.
//
- // We consider constexpr function templates to be referenced in a context
- // that requires a definition to exist whenever they are referenced.
- //
- // FIXME: This instantiates constexpr functions too frequently. If this is
- // really an unevaluated context (and we're not just in the definition of a
- // function template or overload resolution or other cases which we
- // incorrectly consider to be unevaluated contexts), and we're not in a
- // subexpression which we actually need to evaluate (for instance, a
- // template argument, array bound or an expression in a braced-init-list),
- // we are not permitted to instantiate this constexpr function definition.
- //
- // FIXME: This also implicitly defines special members too frequently. They
- // are only supposed to be implicitly defined if they are odr-used, but they
- // are not odr-used from constant expressions in unevaluated contexts.
- // However, they cannot be referenced if they are deleted, and they are
- // deleted whenever the implicit definition of the special member would
- // fail (with very few exceptions).
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func);
+ // That is either when this is an odr-use, or when a usage of a constexpr
+ // function occurs within an evaluatable context.
bool NeedDefinition =
- OdrUse || (Func->isConstexpr() && (Func->isImplicitlyInstantiable() ||
- (MD && !MD->isUserProvided())));
+ OdrUse || (isEvaluatableContext(*this) &&
+ isImplicitlyDefinableConstexprFunction(Func));
// C++14 [temp.expl.spec]p6:
// If a template [...] is explicitly specialized then that specialization
@@ -14123,47 +14158,11 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
Var->setReferenced();
TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
- bool MarkODRUsed = true;
-
- // If the context is not potentially evaluated, this is not an odr-use and
- // does not trigger instantiation.
- if (!IsPotentiallyEvaluatedContext(SemaRef)) {
- if (SemaRef.isUnevaluatedContext())
- return;
-
- // If we don't yet know whether this context is going to end up being an
- // evaluated context, and we're referencing a variable from an enclosing
- // scope, add a potential capture.
- //
- // FIXME: Is this necessary? These contexts are only used for default
- // arguments, where local variables can't be used.
- const bool RefersToEnclosingScope =
- (SemaRef.CurContext != Var->getDeclContext() &&
- Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage());
- if (RefersToEnclosingScope) {
- if (LambdaScopeInfo *const LSI =
- SemaRef.getCurLambda(/*IgnoreCapturedRegions=*/true)) {
- // If a variable could potentially be odr-used, defer marking it so
- // until we finish analyzing the full expression for any
- // lvalue-to-rvalue
- // or discarded value conversions that would obviate odr-use.
- // Add it to the list of potential captures that will be analyzed
- // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
- // unless the variable is a reference that was initialized by a constant
- // expression (this will never need to be captured or odr-used).
- assert(E && "Capture variable should be used in an expression.");
- if (!Var->getType()->isReferenceType() ||
- !IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context))
- LSI->addPotentialCapture(E->IgnoreParens());
- }
- }
- if (!isTemplateInstantiation(TSK))
- return;
-
- // Instantiate, but do not mark as odr-used, variable templates.
- MarkODRUsed = false;
- }
+ bool OdrUseContext = isOdrUseContext(SemaRef);
+ bool NeedDefinition =
+ OdrUseContext || (isEvaluatableContext(SemaRef) &&
+ Var->isUsableInConstantExpressions(SemaRef.Context));
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
@@ -14173,14 +14172,15 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// If this might be a member specialization of a static data member, check
// the specialization is visible. We already did the checks for variable
// template specializations when we created them.
- if (TSK != TSK_Undeclared && !isa<VarTemplateSpecializationDecl>(Var))
+ if (NeedDefinition && TSK != TSK_Undeclared &&
+ !isa<VarTemplateSpecializationDecl>(Var))
SemaRef.checkSpecializationVisibility(Loc, Var);
// Perform implicit instantiation of static data members, static data member
// templates of class templates, and variable template specializations. Delay
// instantiations of variable templates, except for those that could be used
// in a constant expression.
- if (isTemplateInstantiation(TSK)) {
+ if (NeedDefinition && isTemplateInstantiation(TSK)) {
bool TryInstantiating = TSK == TSK_ImplicitInstantiation;
if (TryInstantiating && !isa<VarTemplateSpecializationDecl>(Var)) {
@@ -14219,9 +14219,6 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
}
}
- if (!MarkODRUsed)
- return;
-
// Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies
// the requirements for appearing in a constant expression (5.19) and, if
// it is an object, the lvalue-to-rvalue conversion (4.1)
@@ -14230,14 +14227,41 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// Note that we use the C++11 definition everywhere because nothing in
// C++03 depends on whether we get the C++03 version correct. The second
// part does not apply to references, since they are not objects.
- if (E && IsVariableAConstantExpression(Var, SemaRef.Context)) {
+ if (OdrUseContext && E &&
+ IsVariableAConstantExpression(Var, SemaRef.Context)) {
// A reference initialized by a constant expression can never be
// odr-used, so simply ignore it.
if (!Var->getType()->isReferenceType())
SemaRef.MaybeODRUseExprs.insert(E);
- } else
+ } else if (OdrUseContext) {
MarkVarDeclODRUsed(Var, Loc, SemaRef,
/*MaxFunctionScopeIndex ptr*/ nullptr);
+ } else if (isOdrUseContext(SemaRef, /*SkipDependentUses*/false)) {
+ // If this is a dependent context, we don't need to mark variables as
+ // odr-used, but we may still need to track them for lambda capture.
+ // FIXME: Do we also need to do this inside dependent typeid expressions
+ // (which are modeled as unevaluated at this point)?
+ const bool RefersToEnclosingScope =
+ (SemaRef.CurContext != Var->getDeclContext() &&
+ Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage());
+ if (RefersToEnclosingScope) {
+ if (LambdaScopeInfo *const LSI =
+ SemaRef.getCurLambda(/*IgnoreCapturedRegions=*/true)) {
+ // If a variable could potentially be odr-used, defer marking it so
+ // until we finish analyzing the full expression for any
+ // lvalue-to-rvalue
+ // or discarded value conversions that would obviate odr-use.
+ // Add it to the list of potential captures that will be analyzed
+ // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
+ // unless the variable is a reference that was initialized by a constant
+ // expression (this will never need to be captured or odr-used).
+ assert(E && "Capture variable should be used in an expression.");
+ if (!Var->getType()->isReferenceType() ||
+ !IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context))
+ LSI->addPotentialCapture(E->IgnoreParens());
+ }
+ }
+ }
}
/// \brief Mark a variable referenced, and check whether it is odr-used
@@ -14333,9 +14357,13 @@ void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D,
}
namespace {
- // Mark all of the declarations referenced
+ // Mark all of the declarations used by a type as referenced.
// FIXME: Not fully implemented yet! We need to have a better understanding
- // of when we're entering
+ // of when we're entering a context we should not recurse into.
+ // FIXME: This is and EvaluatedExprMarker are more-or-less equivalent to
+ // TreeTransforms rebuilding the type in a new context. Rather than
+ // duplicating the TreeTransform logic, we should consider reusing it here.
+ // Currently that causes problems when rebuilding LambdaExprs.
class MarkReferencedDecls : public RecursiveASTVisitor<MarkReferencedDecls> {
Sema &S;
SourceLocation Loc;
@@ -14346,33 +14374,28 @@ namespace {
MarkReferencedDecls(Sema &S, SourceLocation Loc) : S(S), Loc(Loc) { }
bool TraverseTemplateArgument(const TemplateArgument &Arg);
- bool TraverseRecordType(RecordType *T);
};
}
bool MarkReferencedDecls::TraverseTemplateArgument(
const TemplateArgument &Arg) {
- if (Arg.getKind() == TemplateArgument::Declaration) {
- if (Decl *D = Arg.getAsDecl())
- S.MarkAnyDeclReferenced(Loc, D, true);
+ {
+ // A non-type template argument is a constant-evaluated context.
+ EnterExpressionEvaluationContext Evaluated(S, Sema::ConstantEvaluated);
+ if (Arg.getKind() == TemplateArgument::Declaration) {
+ if (Decl *D = Arg.getAsDecl())
+ S.MarkAnyDeclReferenced(Loc, D, true);
+ } else if (Arg.getKind() == TemplateArgument::Expression) {
+ S.MarkDeclarationsReferencedInExpr(Arg.getAsExpr(), false);
+ }
}
return Inherited::TraverseTemplateArgument(Arg);
}
-bool MarkReferencedDecls::TraverseRecordType(RecordType *T) {
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) {
- const TemplateArgumentList &Args = Spec->getTemplateArgs();
- return TraverseTemplateArguments(Args.data(), Args.size());
- }
-
- return true;
-}
-
void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) {
MarkReferencedDecls Marker(*this, Loc);
- Marker.TraverseType(Context.getCanonicalType(T));
+ Marker.TraverseType(T);
}
namespace {
@@ -14479,6 +14502,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
const PartialDiagnostic &PD) {
switch (ExprEvalContexts.back().Context) {
case Unevaluated:
+ case UnevaluatedList:
case UnevaluatedAbstract:
case DiscardedStatement:
// The argument will never be evaluated, so don't complain.
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 806a3d813ee8..c9aa99ee383c 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -134,6 +134,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
assert(!AbstractInstanceResult);
switch (SemaRef.ExprEvalContexts.back().Context) {
case Sema::Unevaluated:
+ case Sema::UnevaluatedList:
if (isField && SemaRef.getLangOpts().CPlusPlus11)
AbstractInstanceResult = IMA_Field_Uneval_Context;
break;
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index befee05713e0..45eff5ee6b62 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -6561,6 +6561,13 @@ InitializationSequence::Perform(Sema &S,
break;
}
+ // Promote from an unevaluated context to an unevaluated list context in
+ // C++11 list-initialization; we need to instantiate entities usable in
+ // constant expressions here in order to perform narrowing checks =(
+ EnterExpressionEvaluationContext Evaluated(
+ S, EnterExpressionEvaluationContext::InitList,
+ CurInit.get() && isa<InitListExpr>(CurInit.get()));
+
// C++ [class.abstract]p2:
// no objects of an abstract class can be created except as subobjects
// of a class derived from it
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 3bae69164ffd..a0d574915eba 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -1274,7 +1274,7 @@ static void addFunctionPointerConversion(Sema &S,
ConvTy,
ConvTSI,
/*isInline=*/true, /*isExplicit=*/false,
- /*isConstexpr=*/false,
+ /*isConstexpr=*/S.getLangOpts().CPlusPlus1z,
CallOperator->getBody()->getLocEnd());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
@@ -1565,6 +1565,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
// A lambda-expression shall not appear in an unevaluated operand
// (Clause 5).
case Unevaluated:
+ case UnevaluatedList:
case UnevaluatedAbstract:
// C++1y [expr.const]p2:
// A conditional-expression e is a core constant expression unless the
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 38a7b8c127cc..883e2ae264e9 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -2960,6 +2960,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
AddMethodCandidate(M, Cand, RD, ThisTy, Classification,
+ /*ThisArg=*/nullptr,
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
else if (CtorInfo)
AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
@@ -2972,7 +2973,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
AddMethodTemplateCandidate(
Tmpl, Cand, RD, nullptr, ThisTy, Classification,
- llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ /*ThisArg=*/nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
else if (CtorInfo)
AddTemplateOverloadCandidate(
CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr,
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 33574b9aec35..41f4fa746fc6 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -29,6 +29,7 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
@@ -589,7 +590,6 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
Result.Result = static_cast<unsigned>(TDK);
Result.HasDiagnostic = false;
switch (TDK) {
- case Sema::TDK_Success:
case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_TooManyArguments:
@@ -645,6 +645,10 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
Result.HasDiagnostic = true;
}
break;
+
+ case Sema::TDK_Success:
+ case Sema::TDK_NonDependentConversionFailure:
+ llvm_unreachable("not a deduction failure");
}
return Result;
@@ -660,6 +664,7 @@ void DeductionFailureInfo::Destroy() {
case Sema::TDK_TooFewArguments:
case Sema::TDK_InvalidExplicitArguments:
case Sema::TDK_CUDATargetMismatch:
+ case Sema::TDK_NonDependentConversionFailure:
break;
case Sema::TDK_Inconsistent:
@@ -704,6 +709,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() {
case Sema::TDK_DeducedMismatchNested:
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_CUDATargetMismatch:
+ case Sema::TDK_NonDependentConversionFailure:
return TemplateParameter();
case Sema::TDK_Incomplete:
@@ -735,6 +741,7 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
case Sema::TDK_Underqualified:
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_CUDATargetMismatch:
+ case Sema::TDK_NonDependentConversionFailure:
return nullptr;
case Sema::TDK_DeducedMismatch:
@@ -763,6 +770,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
case Sema::TDK_InvalidExplicitArguments:
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_CUDATargetMismatch:
+ case Sema::TDK_NonDependentConversionFailure:
return nullptr;
case Sema::TDK_Inconsistent:
@@ -791,6 +799,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
case Sema::TDK_InvalidExplicitArguments:
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_CUDATargetMismatch:
+ case Sema::TDK_NonDependentConversionFailure:
return nullptr;
case Sema::TDK_Inconsistent:
@@ -821,8 +830,8 @@ llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
- for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
- i->Conversions[ii].~ImplicitConversionSequence();
+ for (auto &C : i->Conversions)
+ C.~ImplicitConversionSequence();
if (!i->Viable && i->FailureKind == ovl_fail_bad_deduction)
i->DeductionFailure.Destroy();
}
@@ -830,12 +839,20 @@ void OverloadCandidateSet::destroyCandidates() {
void OverloadCandidateSet::clear() {
destroyCandidates();
- ConversionSequenceAllocator.Reset();
- NumInlineSequences = 0;
+ // DiagnoseIfAttrs are just pointers, so we don't need to destroy them.
+ SlabAllocator.Reset();
+ NumInlineBytesUsed = 0;
Candidates.clear();
Functions.clear();
}
+DiagnoseIfAttr **
+OverloadCandidateSet::addDiagnoseIfComplaints(ArrayRef<DiagnoseIfAttr *> CA) {
+ auto *DIA = slabAllocate<DiagnoseIfAttr *>(CA.size());
+ std::uninitialized_copy(CA.begin(), CA.end(), DIA);
+ return DIA;
+}
+
namespace {
class UnbridgedCastsSet {
struct Entry {
@@ -5814,6 +5831,28 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
return false;
}
+static void initDiagnoseIfComplaint(Sema &S, OverloadCandidateSet &CandidateSet,
+ OverloadCandidate &Candidate,
+ FunctionDecl *Function,
+ ArrayRef<Expr *> Args,
+ bool MissingImplicitThis = false,
+ Expr *ExplicitThis = nullptr) {
+ SmallVector<DiagnoseIfAttr *, 8> Results;
+ if (DiagnoseIfAttr *DIA = S.checkArgDependentDiagnoseIf(
+ Function, Args, Results, MissingImplicitThis, ExplicitThis)) {
+ Results.clear();
+ Results.push_back(DIA);
+ }
+
+ Candidate.NumTriggeredDiagnoseIfs = Results.size();
+ if (Results.empty())
+ Candidate.DiagnoseIfInfo = nullptr;
+ else if (Results.size() == 1)
+ Candidate.DiagnoseIfInfo = Results[0];
+ else
+ Candidate.DiagnoseIfInfo = CandidateSet.addDiagnoseIfComplaints(Results);
+}
+
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments. If
/// @p SuppressUserConversions, then don't allow user-defined
@@ -5829,7 +5868,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions,
bool PartialOverloading,
- bool AllowExplicit) {
+ bool AllowExplicit,
+ ConversionSequenceList EarlyConversions) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -5845,10 +5885,11 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// function, e.g., X::f(). We use an empty type for the implied
// object argument (C++ [over.call.func]p3), and the acting context
// is irrelevant.
- AddMethodCandidate(Method, FoundDecl, Method->getParent(),
- QualType(), Expr::Classification::makeSimpleLValue(),
- Args, CandidateSet, SuppressUserConversions,
- PartialOverloading);
+ AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
+ Expr::Classification::makeSimpleLValue(),
+ /*ThisArg=*/nullptr, Args, CandidateSet,
+ SuppressUserConversions, PartialOverloading,
+ EarlyConversions);
return;
}
// We treat a constructor like a non-member function, since its object
@@ -5881,7 +5922,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate
- OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
+ OverloadCandidate &Candidate =
+ CandidateSet.addCandidate(Args.size(), EarlyConversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Function;
Candidate.Viable = true;
@@ -5945,7 +5987,10 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
- if (ArgIdx < NumParams) {
+ if (Candidate.Conversions[ArgIdx].isInitialized()) {
+ // We already formed a conversion sequence for this parameter during
+ // template argument deduction.
+ } else if (ArgIdx < NumParams) {
// (C++ 13.3.2p3): for F to be a viable function, there shall
// exist for each argument an implicit conversion sequence
// (13.3.3.1) that converts that argument to the corresponding
@@ -5971,6 +6016,31 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
}
}
+ // C++ [over.best.ics]p4+: (proposed DR resolution)
+ // If the target is the first parameter of an inherited constructor when
+ // constructing an object of type C with an argument list that has exactly
+ // one expression, an implicit conversion sequence cannot be formed if C is
+ // reference-related to the type that the argument would have after the
+ // application of the user-defined conversion (if any) and before the final
+ // standard conversion sequence.
+ auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl.getDecl());
+ if (Shadow && Args.size() == 1 && !isa<InitListExpr>(Args.front())) {
+ bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion;
+ QualType ConvertedArgumentType = Args.front()->getType();
+ if (Candidate.Conversions[0].isUserDefined())
+ ConvertedArgumentType =
+ Candidate.Conversions[0].UserDefined.After.getFromType();
+ if (CompareReferenceRelationship(Args.front()->getLocStart(),
+ Context.getRecordType(Shadow->getParent()),
+ ConvertedArgumentType, DerivedToBase,
+ ObjCConversion,
+ ObjCLifetimeConversion) >= Ref_Related) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_inhctor_slice;
+ return;
+ }
+ }
+
if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
@@ -5983,6 +6053,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
Candidate.FailureKind = ovl_fail_ext_disabled;
return;
}
+
+ initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Function, Args);
}
ObjCMethodDecl *
@@ -6095,66 +6167,87 @@ getOrderedEnableIfAttrs(const FunctionDecl *Function) {
return Result;
}
-EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
- bool MissingImplicitThis) {
- auto EnableIfAttrs = getOrderedEnableIfAttrs(Function);
- if (EnableIfAttrs.empty())
- return nullptr;
-
- SFINAETrap Trap(*this);
- SmallVector<Expr *, 16> ConvertedArgs;
- bool InitializationFailed = false;
+static bool
+convertArgsForAvailabilityChecks(Sema &S, FunctionDecl *Function, Expr *ThisArg,
+ ArrayRef<Expr *> Args, Sema::SFINAETrap &Trap,
+ bool MissingImplicitThis, Expr *&ConvertedThis,
+ SmallVectorImpl<Expr *> &ConvertedArgs) {
+ if (ThisArg) {
+ CXXMethodDecl *Method = cast<CXXMethodDecl>(Function);
+ assert(!isa<CXXConstructorDecl>(Method) &&
+ "Shouldn't have `this` for ctors!");
+ assert(!Method->isStatic() && "Shouldn't have `this` for static methods!");
+ ExprResult R = S.PerformObjectArgumentInitialization(
+ ThisArg, /*Qualifier=*/nullptr, Method, Method);
+ if (R.isInvalid())
+ return false;
+ ConvertedThis = R.get();
+ } else {
+ if (auto *MD = dyn_cast<CXXMethodDecl>(Function)) {
+ (void)MD;
+ assert((MissingImplicitThis || MD->isStatic() ||
+ isa<CXXConstructorDecl>(MD)) &&
+ "Expected `this` for non-ctor instance methods");
+ }
+ ConvertedThis = nullptr;
+ }
// Ignore any variadic arguments. Converting them is pointless, since the
- // user can't refer to them in the enable_if condition.
+ // user can't refer to them in the function condition.
unsigned ArgSizeNoVarargs = std::min(Function->param_size(), Args.size());
// Convert the arguments.
for (unsigned I = 0; I != ArgSizeNoVarargs; ++I) {
ExprResult R;
- if (I == 0 && !MissingImplicitThis && isa<CXXMethodDecl>(Function) &&
- !cast<CXXMethodDecl>(Function)->isStatic() &&
- !isa<CXXConstructorDecl>(Function)) {
- CXXMethodDecl *Method = cast<CXXMethodDecl>(Function);
- R = PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr,
- Method, Method);
- } else {
- R = PerformCopyInitialization(InitializedEntity::InitializeParameter(
- Context, Function->getParamDecl(I)),
+ R = S.PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ S.Context, Function->getParamDecl(I)),
SourceLocation(), Args[I]);
- }
- if (R.isInvalid()) {
- InitializationFailed = true;
- break;
- }
+ if (R.isInvalid())
+ return false;
ConvertedArgs.push_back(R.get());
}
- if (InitializationFailed || Trap.hasErrorOccurred())
- return EnableIfAttrs[0];
+ if (Trap.hasErrorOccurred())
+ return false;
// Push default arguments if needed.
if (!Function->isVariadic() && Args.size() < Function->getNumParams()) {
for (unsigned i = Args.size(), e = Function->getNumParams(); i != e; ++i) {
ParmVarDecl *P = Function->getParamDecl(i);
- ExprResult R = PerformCopyInitialization(
- InitializedEntity::InitializeParameter(Context,
+ ExprResult R = S.PerformCopyInitialization(
+ InitializedEntity::InitializeParameter(S.Context,
Function->getParamDecl(i)),
SourceLocation(),
P->hasUninstantiatedDefaultArg() ? P->getUninstantiatedDefaultArg()
: P->getDefaultArg());
- if (R.isInvalid()) {
- InitializationFailed = true;
- break;
- }
+ if (R.isInvalid())
+ return false;
ConvertedArgs.push_back(R.get());
}
- if (InitializationFailed || Trap.hasErrorOccurred())
- return EnableIfAttrs[0];
+ if (Trap.hasErrorOccurred())
+ return false;
}
+ return true;
+}
+
+EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
+ bool MissingImplicitThis) {
+ SmallVector<EnableIfAttr *, 4> EnableIfAttrs =
+ getOrderedEnableIfAttrs(Function);
+ if (EnableIfAttrs.empty())
+ return nullptr;
+
+ SFINAETrap Trap(*this);
+ SmallVector<Expr *, 16> ConvertedArgs;
+ // FIXME: We should look into making enable_if late-parsed.
+ Expr *DiscardedThis;
+ if (!convertArgsForAvailabilityChecks(
+ *this, Function, /*ThisArg=*/nullptr, Args, Trap,
+ /*MissingImplicitThis=*/true, DiscardedThis, ConvertedArgs))
+ return EnableIfAttrs[0];
for (auto *EIA : EnableIfAttrs) {
APValue Result;
@@ -6170,6 +6263,87 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
return nullptr;
}
+static bool gatherDiagnoseIfAttrs(FunctionDecl *Function, bool ArgDependent,
+ SmallVectorImpl<DiagnoseIfAttr *> &Errors,
+ SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal) {
+ for (auto *DIA : Function->specific_attrs<DiagnoseIfAttr>())
+ if (ArgDependent == DIA->getArgDependent()) {
+ if (DIA->isError())
+ Errors.push_back(DIA);
+ else
+ Nonfatal.push_back(DIA);
+ }
+
+ return !Errors.empty() || !Nonfatal.empty();
+}
+
+template <typename CheckFn>
+static DiagnoseIfAttr *
+checkDiagnoseIfAttrsWith(const SmallVectorImpl<DiagnoseIfAttr *> &Errors,
+ SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
+ CheckFn &&IsSuccessful) {
+ // Note that diagnose_if attributes are late-parsed, so they appear in the
+ // correct order (unlike enable_if attributes).
+ auto ErrAttr = llvm::find_if(Errors, IsSuccessful);
+ if (ErrAttr != Errors.end())
+ return *ErrAttr;
+
+ llvm::erase_if(Nonfatal, [&](DiagnoseIfAttr *A) { return !IsSuccessful(A); });
+ return nullptr;
+}
+
+DiagnoseIfAttr *
+Sema::checkArgDependentDiagnoseIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
+ SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
+ bool MissingImplicitThis,
+ Expr *ThisArg) {
+ SmallVector<DiagnoseIfAttr *, 4> Errors;
+ if (!gatherDiagnoseIfAttrs(Function, /*ArgDependent=*/true, Errors, Nonfatal))
+ return nullptr;
+
+ SFINAETrap Trap(*this);
+ SmallVector<Expr *, 16> ConvertedArgs;
+ Expr *ConvertedThis;
+ if (!convertArgsForAvailabilityChecks(*this, Function, ThisArg, Args, Trap,
+ MissingImplicitThis, ConvertedThis,
+ ConvertedArgs))
+ return nullptr;
+
+ return checkDiagnoseIfAttrsWith(Errors, Nonfatal, [&](DiagnoseIfAttr *DIA) {
+ APValue Result;
+ // It's sane to use the same ConvertedArgs for any redecl of this function,
+ // since EvaluateWithSubstitution only cares about the position of each
+ // argument in the arg list, not the ParmVarDecl* it maps to.
+ if (!DIA->getCond()->EvaluateWithSubstitution(
+ Result, Context, DIA->getParent(), ConvertedArgs, ConvertedThis))
+ return false;
+ return Result.isInt() && Result.getInt().getBoolValue();
+ });
+}
+
+DiagnoseIfAttr *Sema::checkArgIndependentDiagnoseIf(
+ FunctionDecl *Function, SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal) {
+ SmallVector<DiagnoseIfAttr *, 4> Errors;
+ if (!gatherDiagnoseIfAttrs(Function, /*ArgDependent=*/false, Errors,
+ Nonfatal))
+ return nullptr;
+
+ return checkDiagnoseIfAttrsWith(Errors, Nonfatal, [&](DiagnoseIfAttr *DIA) {
+ bool Result;
+ return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) &&
+ Result;
+ });
+}
+
+void Sema::emitDiagnoseIfDiagnostic(SourceLocation Loc,
+ const DiagnoseIfAttr *DIA) {
+ auto Code = DIA->isError() ? diag::err_diagnose_if_succeeded
+ : diag::warn_diagnose_if_succeeded;
+ Diag(Loc, Code) << DIA->getMessage();
+ Diag(DIA->getLocation(), diag::note_from_diagnose_if)
+ << DIA->getParent() << DIA->getCond()->getSourceRange();
+}
+
/// \brief Add all of the function declarations in the given function set to
/// the overload candidate set.
void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
@@ -6185,7 +6359,7 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
cast<CXXMethodDecl>(FD)->getParent(),
Args[0]->getType(), Args[0]->Classify(Context),
- Args.slice(1), CandidateSet,
+ Args[0], Args.slice(1), CandidateSet,
SuppressUserConversions, PartialOverloading);
else
AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet,
@@ -6194,13 +6368,12 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(D);
if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) &&
!cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic())
- AddMethodTemplateCandidate(FunTmpl, F.getPair(),
- cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
- ExplicitTemplateArgs,
- Args[0]->getType(),
- Args[0]->Classify(Context), Args.slice(1),
- CandidateSet, SuppressUserConversions,
- PartialOverloading);
+ AddMethodTemplateCandidate(
+ FunTmpl, F.getPair(),
+ cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
+ ExplicitTemplateArgs, Args[0]->getType(),
+ Args[0]->Classify(Context), Args[0], Args.slice(1), CandidateSet,
+ SuppressUserConversions, PartialOverloading);
else
AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
ExplicitTemplateArgs, Args,
@@ -6215,6 +6388,7 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
QualType ObjectType,
Expr::Classification ObjectClassification,
+ Expr *ThisArg,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
@@ -6230,12 +6404,12 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,
/*ExplicitArgs*/ nullptr,
ObjectType, ObjectClassification,
- Args, CandidateSet,
+ ThisArg, Args, CandidateSet,
SuppressUserConversions);
} else {
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
ObjectType, ObjectClassification,
- Args,
+ ThisArg, Args,
CandidateSet, SuppressUserConversions);
}
}
@@ -6251,10 +6425,11 @@ void
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
- ArrayRef<Expr *> Args,
+ Expr *ThisArg, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions,
- bool PartialOverloading) {
+ bool PartialOverloading,
+ ConversionSequenceList EarlyConversions) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
@@ -6275,7 +6450,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate
- OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size() + 1);
+ OverloadCandidate &Candidate =
+ CandidateSet.addCandidate(Args.size() + 1, EarlyConversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Method;
Candidate.IsSurrogate = false;
@@ -6337,7 +6513,10 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
- if (ArgIdx < NumParams) {
+ if (Candidate.Conversions[ArgIdx + 1].isInitialized()) {
+ // We already formed a conversion sequence for this parameter during
+ // template argument deduction.
+ } else if (ArgIdx < NumParams) {
// (C++ 13.3.2p3): for F to be a viable function, there shall
// exist for each argument an implicit conversion sequence
// (13.3.3.1) that converts that argument to the corresponding
@@ -6368,6 +6547,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
+
+ initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Method, Args,
+ /*MissingImplicitThis=*/!ThisArg, ThisArg);
}
/// \brief Add a C++ member function template as a candidate to the candidate
@@ -6380,6 +6562,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
+ Expr *ThisArg,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
@@ -6398,19 +6581,30 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
// functions.
TemplateDeductionInfo Info(CandidateSet.getLocation());
FunctionDecl *Specialization = nullptr;
- if (TemplateDeductionResult Result
- = DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, Args,
- Specialization, Info, PartialOverloading)) {
- OverloadCandidate &Candidate = CandidateSet.addCandidate();
+ ConversionSequenceList Conversions;
+ if (TemplateDeductionResult Result = DeduceTemplateArguments(
+ MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info,
+ PartialOverloading, [&](ArrayRef<QualType> ParamTypes) {
+ return CheckNonDependentConversions(
+ MethodTmpl, ParamTypes, Args, CandidateSet, Conversions,
+ SuppressUserConversions, ActingContext, ObjectType,
+ ObjectClassification);
+ })) {
+ OverloadCandidate &Candidate =
+ CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = MethodTmpl->getTemplatedDecl();
Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
- Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
- Info);
+ if (Result == TDK_NonDependentConversionFailure)
+ Candidate.FailureKind = ovl_fail_bad_conversion;
+ else {
+ Candidate.FailureKind = ovl_fail_bad_deduction;
+ Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
+ Info);
+ }
return;
}
@@ -6420,8 +6614,9 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
assert(isa<CXXMethodDecl>(Specialization) &&
"Specialization is not a member function?");
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
- ActingContext, ObjectType, ObjectClassification, Args,
- CandidateSet, SuppressUserConversions, PartialOverloading);
+ ActingContext, ObjectType, ObjectClassification,
+ /*ThisArg=*/ThisArg, Args, CandidateSet,
+ SuppressUserConversions, PartialOverloading, Conversions);
}
/// \brief Add a C++ function template specialization as a candidate
@@ -6449,19 +6644,29 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// functions.
TemplateDeductionInfo Info(CandidateSet.getLocation());
FunctionDecl *Specialization = nullptr;
- if (TemplateDeductionResult Result
- = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, Args,
- Specialization, Info, PartialOverloading)) {
- OverloadCandidate &Candidate = CandidateSet.addCandidate();
+ ConversionSequenceList Conversions;
+ if (TemplateDeductionResult Result = DeduceTemplateArguments(
+ FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info,
+ PartialOverloading, [&](ArrayRef<QualType> ParamTypes) {
+ return CheckNonDependentConversions(FunctionTemplate, ParamTypes,
+ Args, CandidateSet, Conversions,
+ SuppressUserConversions);
+ })) {
+ OverloadCandidate &Candidate =
+ CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
- Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
- Info);
+ if (Result == TDK_NonDependentConversionFailure)
+ Candidate.FailureKind = ovl_fail_bad_conversion;
+ else {
+ Candidate.FailureKind = ovl_fail_bad_deduction;
+ Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
+ Info);
+ }
return;
}
@@ -6469,7 +6674,64 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet,
- SuppressUserConversions, PartialOverloading);
+ SuppressUserConversions, PartialOverloading,
+ /*AllowExplicit*/false, Conversions);
+}
+
+/// Check that implicit conversion sequences can be formed for each argument
+/// whose corresponding parameter has a non-dependent type, per DR1391's
+/// [temp.deduct.call]p10.
+bool Sema::CheckNonDependentConversions(
+ FunctionTemplateDecl *FunctionTemplate, ArrayRef<QualType> ParamTypes,
+ ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet,
+ ConversionSequenceList &Conversions, bool SuppressUserConversions,
+ CXXRecordDecl *ActingContext, QualType ObjectType,
+ Expr::Classification ObjectClassification) {
+ // FIXME: The cases in which we allow explicit conversions for constructor
+ // arguments never consider calling a constructor template. It's not clear
+ // that is correct.
+ const bool AllowExplicit = false;
+
+ auto *FD = FunctionTemplate->getTemplatedDecl();
+ auto *Method = dyn_cast<CXXMethodDecl>(FD);
+ bool HasThisConversion = Method && !isa<CXXConstructorDecl>(Method);
+ unsigned ThisConversions = HasThisConversion ? 1 : 0;
+
+ Conversions =
+ CandidateSet.allocateConversionSequences(ThisConversions + Args.size());
+
+ // Overload resolution is always an unevaluated context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+
+ // For a method call, check the 'this' conversion here too. DR1391 doesn't
+ // require that, but this check should never result in a hard error, and
+ // overload resolution is permitted to sidestep instantiations.
+ if (HasThisConversion && !cast<CXXMethodDecl>(FD)->isStatic() &&
+ !ObjectType.isNull()) {
+ Conversions[0] = TryObjectArgumentInitialization(
+ *this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
+ Method, ActingContext);
+ if (Conversions[0].isBad())
+ return true;
+ }
+
+ for (unsigned I = 0, N = std::min(ParamTypes.size(), Args.size()); I != N;
+ ++I) {
+ QualType ParamType = ParamTypes[I];
+ if (!ParamType->isDependentType()) {
+ Conversions[ThisConversions + I]
+ = TryCopyInitialization(*this, Args[I], ParamType,
+ SuppressUserConversions,
+ /*InOverloadResolution=*/true,
+ /*AllowObjCWritebackConversion=*/
+ getLangOpts().ObjCAutoRefCount,
+ AllowExplicit);
+ if (Conversions[ThisConversions + I].isBad())
+ return true;
+ }
+ }
+
+ return false;
}
/// Determine whether this is an allowable conversion from the result
@@ -6677,6 +6939,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
+
+ initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Conversion, None, false, From);
}
/// \brief Adds a conversion function template specialization
@@ -6829,6 +7093,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
+
+ initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Conversion, None);
}
/// \brief Add overload candidates for overloaded operators that are
@@ -6877,10 +7143,8 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
Oper != OperEnd;
++Oper)
AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
- Args[0]->Classify(Context),
- Args.slice(1),
- CandidateSet,
- /* SuppressUserConversions = */ false);
+ Args[0]->Classify(Context), Args[0], Args.slice(1),
+ CandidateSet, /*SuppressUserConversions=*/false);
}
}
@@ -8708,8 +8972,8 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
// Define functions that don't require ill-formed conversions for a given
// argument to be better candidates than functions that do.
- unsigned NumArgs = Cand1.NumConversions;
- assert(Cand2.NumConversions == NumArgs && "Overload candidate mismatch");
+ unsigned NumArgs = Cand1.Conversions.size();
+ assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch");
bool HasBetterConversion = false;
for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
bool Cand1Bad = IsIllFormedConversion(Cand1.Conversions[ArgIdx]);
@@ -8911,6 +9175,17 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations(
}
}
+static bool isCandidateUnavailableDueToDiagnoseIf(const OverloadCandidate &OC) {
+ ArrayRef<DiagnoseIfAttr *> Info = OC.getDiagnoseIfInfo();
+ if (!Info.empty() && Info[0]->isError())
+ return true;
+
+ assert(llvm::all_of(Info,
+ [](const DiagnoseIfAttr *A) { return !A->isError(); }) &&
+ "DiagnoseIf info shouldn't have mixed warnings and errors.");
+ return false;
+}
+
/// \brief Computes the best viable function (C++ 13.3.3)
/// within an overload candidate set.
///
@@ -8989,13 +9264,19 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// Best is the best viable function.
if (Best->Function &&
(Best->Function->isDeleted() ||
- S.isFunctionConsideredUnavailable(Best->Function)))
+ S.isFunctionConsideredUnavailable(Best->Function) ||
+ isCandidateUnavailableDueToDiagnoseIf(*Best)))
return OR_Deleted;
if (!EquivalentCands.empty())
S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function,
EquivalentCands);
+ for (const auto *W : Best->getDiagnoseIfInfo()) {
+ assert(W->isWarning() && "Errors should've been caught earlier!");
+ S.emitDiagnoseIfDiagnostic(Loc, W);
+ }
+
return OR_Success;
}
@@ -9836,7 +10117,7 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
EnableIfAttr *Attr = static_cast<EnableIfAttr*>(Cand->DeductionFailure.Data);
S.Diag(Callee->getLocation(),
- diag::note_ovl_candidate_disabled_by_enable_if_attr)
+ diag::note_ovl_candidate_disabled_by_function_cond_attr)
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
}
@@ -9866,21 +10147,28 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
FunctionDecl *Fn = Cand->Function;
// Note deleted candidates, but only if they're viable.
- if (Cand->Viable && (Fn->isDeleted() ||
- S.isFunctionConsideredUnavailable(Fn))) {
- std::string FnDesc;
- OverloadCandidateKind FnKind =
+ if (Cand->Viable) {
+ if (Fn->isDeleted() || S.isFunctionConsideredUnavailable(Fn)) {
+ std::string FnDesc;
+ OverloadCandidateKind FnKind =
ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc);
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
- << FnKind << FnDesc
- << (Fn->isDeleted() ? (Fn->isDeletedAsWritten() ? 1 : 2) : 0);
- MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
- return;
- }
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
+ << FnKind << FnDesc
+ << (Fn->isDeleted() ? (Fn->isDeletedAsWritten() ? 1 : 2) : 0);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
+ return;
+ }
+ if (isCandidateUnavailableDueToDiagnoseIf(*Cand)) {
+ auto *A = Cand->DiagnoseIfInfo.get<DiagnoseIfAttr *>();
+ assert(A->isError() && "Non-error diagnose_if disables a candidate?");
+ S.Diag(Cand->Function->getLocation(),
+ diag::note_ovl_candidate_disabled_by_function_cond_attr)
+ << A->getCond()->getSourceRange() << A->getMessage();
+ return;
+ }
- // We don't really have anything else to say about viable candidates.
- if (Cand->Viable) {
+ // We don't really have anything else to say about viable candidates.
S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
return;
}
@@ -9908,7 +10196,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_bad_conversion: {
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
- for (unsigned N = Cand->NumConversions; I != N; ++I)
+ for (unsigned N = Cand->Conversions.size(); I != N; ++I)
if (Cand->Conversions[I].isBad())
return DiagnoseBadConversion(S, Cand, I, TakingCandidateAddress);
@@ -9927,6 +10215,12 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_ext_disabled:
return DiagnoseOpenCLExtensionDisabled(S, Cand);
+ case ovl_fail_inhctor_slice:
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_inherited_constructor_slice);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
+ return;
+
case ovl_fail_addr_not_available: {
bool Available = checkAddressOfCandidateIsAvailable(S, Cand->Function);
(void)Available;
@@ -9971,12 +10265,12 @@ static void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
SourceLocation OpLoc,
OverloadCandidate *Cand) {
- assert(Cand->NumConversions <= 2 && "builtin operator is not binary");
+ assert(Cand->Conversions.size() <= 2 && "builtin operator is not binary");
std::string TypeStr("operator");
TypeStr += Opc;
TypeStr += "(";
TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString();
- if (Cand->NumConversions == 1) {
+ if (Cand->Conversions.size() == 1) {
TypeStr += ")";
S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr;
} else {
@@ -9989,9 +10283,7 @@ static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
static void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
OverloadCandidate *Cand) {
- unsigned NoOperands = Cand->NumConversions;
- for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
- const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
+ for (const ImplicitConversionSequence &ICS : Cand->Conversions) {
if (ICS.isBad()) break; // all meaningless after first invalid
if (!ICS.isAmbiguous()) continue;
@@ -10011,7 +10303,8 @@ static SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) {
static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
switch ((Sema::TemplateDeductionResult)DFI.Result) {
case Sema::TDK_Success:
- llvm_unreachable("TDK_success while diagnosing bad deduction");
+ case Sema::TDK_NonDependentConversionFailure:
+ llvm_unreachable("non-deduction failure while diagnosing bad deduction");
case Sema::TDK_Invalid:
case Sema::TDK_Incomplete:
@@ -10114,11 +10407,11 @@ struct CompareOverloadCandidatesForDisplay {
// If there's any ordering between the defined conversions...
// FIXME: this might not be transitive.
- assert(L->NumConversions == R->NumConversions);
+ assert(L->Conversions.size() == R->Conversions.size());
int leftBetter = 0;
unsigned I = (L->IgnoreObjectArgument || R->IgnoreObjectArgument);
- for (unsigned E = L->NumConversions; I != E; ++I) {
+ for (unsigned E = L->Conversions.size(); I != E; ++I) {
switch (CompareImplicitConversionSequences(S, Loc,
L->Conversions[I],
R->Conversions[I])) {
@@ -10167,7 +10460,8 @@ struct CompareOverloadCandidatesForDisplay {
}
/// CompleteNonViableCandidate - Normally, overload resolution only
-/// computes up to the first. Produces the FixIt set if possible.
+/// computes up to the first bad conversion. Produces the FixIt set if
+/// possible.
static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
ArrayRef<Expr *> Args) {
assert(!Cand->Viable);
@@ -10180,30 +10474,24 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
// Use a implicit copy initialization to check conversion fixes.
Cand->Fix.setConversionChecker(TryCopyInitialization);
- // Skip forward to the first bad conversion.
- unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0);
- unsigned ConvCount = Cand->NumConversions;
- while (true) {
+ // Attempt to fix the bad conversion.
+ unsigned ConvCount = Cand->Conversions.size();
+ for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); /**/;
+ ++ConvIdx) {
assert(ConvIdx != ConvCount && "no bad conversion in candidate");
- ConvIdx++;
- if (Cand->Conversions[ConvIdx - 1].isBad()) {
- Unfixable = !Cand->TryToFixBadConversion(ConvIdx - 1, S);
+ if (Cand->Conversions[ConvIdx].isInitialized() &&
+ Cand->Conversions[ConvIdx].isBad()) {
+ Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S);
break;
}
}
- if (ConvIdx == ConvCount)
- return;
-
- assert(!Cand->Conversions[ConvIdx].isInitialized() &&
- "remaining conversion is initialized?");
-
// FIXME: this should probably be preserved from the overload
// operation somehow.
bool SuppressUserConversions = false;
- const FunctionProtoType* Proto;
- unsigned ArgIdx = ConvIdx;
+ const FunctionProtoType *Proto;
+ unsigned ArgIdx = 0;
if (Cand->IsSurrogate) {
QualType ConvType
@@ -10211,40 +10499,56 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
ConvType = ConvPtrType->getPointeeType();
Proto = ConvType->getAs<FunctionProtoType>();
- ArgIdx--;
+ ArgIdx = 1;
} else if (Cand->Function) {
Proto = Cand->Function->getType()->getAs<FunctionProtoType>();
if (isa<CXXMethodDecl>(Cand->Function) &&
!isa<CXXConstructorDecl>(Cand->Function))
- ArgIdx--;
+ ArgIdx = 1;
} else {
// Builtin binary operator with a bad first conversion.
assert(ConvCount <= 3);
- for (; ConvIdx != ConvCount; ++ConvIdx)
- Cand->Conversions[ConvIdx]
- = TryCopyInitialization(S, Args[ConvIdx],
- Cand->BuiltinTypes.ParamTypes[ConvIdx],
- SuppressUserConversions,
- /*InOverloadResolution*/ true,
- /*AllowObjCWritebackConversion=*/
- S.getLangOpts().ObjCAutoRefCount);
+ for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0);
+ ConvIdx != ConvCount; ++ConvIdx) {
+ if (Cand->Conversions[ConvIdx].isInitialized())
+ continue;
+ if (Cand->BuiltinTypes.ParamTypes[ConvIdx]->isDependentType())
+ Cand->Conversions[ConvIdx].setAsIdentityConversion(
+ Args[ConvIdx]->getType());
+ else
+ Cand->Conversions[ConvIdx] = TryCopyInitialization(
+ S, Args[ConvIdx], Cand->BuiltinTypes.ParamTypes[ConvIdx],
+ SuppressUserConversions,
+ /*InOverloadResolution*/ true,
+ /*AllowObjCWritebackConversion=*/
+ S.getLangOpts().ObjCAutoRefCount);
+ // FIXME: If the conversion is bad, try to fix it.
+ }
return;
}
// Fill in the rest of the conversions.
unsigned NumParams = Proto->getNumParams();
- for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
- if (ArgIdx < NumParams) {
- Cand->Conversions[ConvIdx] = TryCopyInitialization(
- S, Args[ArgIdx], Proto->getParamType(ArgIdx), SuppressUserConversions,
- /*InOverloadResolution=*/true,
- /*AllowObjCWritebackConversion=*/
- S.getLangOpts().ObjCAutoRefCount);
- // Store the FixIt in the candidate if it exists.
- if (!Unfixable && Cand->Conversions[ConvIdx].isBad())
- Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S);
- }
- else
+ for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0);
+ ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
+ if (Cand->Conversions[ConvIdx].isInitialized()) {
+ // Found the bad conversion.
+ } else if (ArgIdx < NumParams) {
+ if (Proto->getParamType(ArgIdx)->isDependentType())
+ Cand->Conversions[ConvIdx].setAsIdentityConversion(
+ Args[ArgIdx]->getType());
+ else {
+ Cand->Conversions[ConvIdx] =
+ TryCopyInitialization(S, Args[ArgIdx], Proto->getParamType(ArgIdx),
+ SuppressUserConversions,
+ /*InOverloadResolution=*/true,
+ /*AllowObjCWritebackConversion=*/
+ S.getLangOpts().ObjCAutoRefCount);
+ // Store the FixIt in the candidate if it exists.
+ if (!Unfixable && Cand->Conversions[ConvIdx].isBad())
+ Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S);
+ }
+ } else
Cand->Conversions[ConvIdx].setEllipsis();
}
}
@@ -12429,6 +12733,16 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
TemplateArgs = &TemplateArgsBuffer;
}
+ // Poor-programmer's Lazy<Expr *>; isImplicitAccess requires stripping
+ // parens/casts, which would be nice to avoid potentially doing multiple
+ // times.
+ llvm::Optional<Expr *> UnresolvedBase;
+ auto GetUnresolvedBase = [&] {
+ if (!UnresolvedBase.hasValue())
+ UnresolvedBase =
+ UnresExpr->isImplicitAccess() ? nullptr : UnresExpr->getBase();
+ return *UnresolvedBase;
+ };
for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(),
E = UnresExpr->decls_end(); I != E; ++I) {
@@ -12449,14 +12763,15 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
continue;
AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType,
- ObjectClassification, Args, CandidateSet,
+ ObjectClassification,
+ /*ThisArg=*/GetUnresolvedBase(), Args, CandidateSet,
/*SuppressUserConversions=*/false);
} else {
- AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
- I.getPair(), ActingDC, TemplateArgs,
- ObjectType, ObjectClassification,
- Args, CandidateSet,
- /*SuppressUsedConversions=*/false);
+ AddMethodTemplateCandidate(
+ cast<FunctionTemplateDecl>(Func), I.getPair(), ActingDC,
+ TemplateArgs, ObjectType, ObjectClassification,
+ /*ThisArg=*/GetUnresolvedBase(), Args, CandidateSet,
+ /*SuppressUsedConversions=*/false);
}
}
@@ -12569,10 +12884,20 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
diag::err_ovl_no_viable_member_function_in_call)
<< Method << Method->getSourceRange();
Diag(Method->getLocation(),
- diag::note_ovl_candidate_disabled_by_enable_if_attr)
+ diag::note_ovl_candidate_disabled_by_function_cond_attr)
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
return ExprError();
}
+
+ SmallVector<DiagnoseIfAttr *, 4> Nonfatal;
+ if (const DiagnoseIfAttr *Attr = checkArgDependentDiagnoseIf(
+ Method, Args, Nonfatal, false, MemE->getBase())) {
+ emitDiagnoseIfDiagnostic(MemE->getMemberLoc(), Attr);
+ return ExprError();
+ }
+
+ for (const auto *Attr : Nonfatal)
+ emitDiagnoseIfDiagnostic(MemE->getMemberLoc(), Attr);
}
if ((isa<CXXConstructorDecl>(CurContext) ||
@@ -12652,7 +12977,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
Oper != OperEnd; ++Oper) {
AddMethodCandidate(Oper.getPair(), Object.get()->getType(),
Object.get()->Classify(Context),
- Args, CandidateSet,
+ Object.get(), Args, CandidateSet,
/*SuppressUserConversions=*/ false);
}
@@ -12928,7 +13253,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context),
- None, CandidateSet, /*SuppressUserConversions=*/false);
+ Base, None, CandidateSet,
+ /*SuppressUserConversions=*/false);
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 66a10ef7993e..795e6025d96f 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -5158,6 +5158,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return Arg;
}
+ // The initialization of the parameter from the argument is
+ // a constant-evaluated context.
+ EnterExpressionEvaluationContext ConstantEvaluated(*this,
+ Sema::ConstantEvaluated);
+
if (getLangOpts().CPlusPlus1z) {
// C++1z [temp.arg.nontype]p1:
// A template-argument for a non-type template parameter shall be
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index b79904c0a703..93e796ee9668 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -669,6 +669,19 @@ public:
Info.PendingDeducedPacks[Pack.Index] = Pack.Outer;
}
+ /// Determine whether this pack has already been partially expanded into a
+ /// sequence of (prior) function parameters / template arguments.
+ bool isPartiallyExpanded() {
+ if (Packs.size() != 1 || !S.CurrentInstantiationScope)
+ return false;
+
+ auto *PartiallySubstitutedPack =
+ S.CurrentInstantiationScope->getPartiallySubstitutedPack();
+ return PartiallySubstitutedPack &&
+ getDepthAndIndex(PartiallySubstitutedPack) ==
+ std::make_pair(Info.getDeducedDepth(), Packs.front().Index);
+ }
+
/// Move to deducing the next element in each pack that is being deduced.
void nextPackElement() {
// Capture the deduced template arguments for each parameter pack expanded
@@ -2552,6 +2565,12 @@ static bool isSimpleTemplateIdType(QualType T) {
return false;
}
+static void
+MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
+ bool OnlyDeduced,
+ unsigned Level,
+ llvm::SmallBitVector &Deduced);
+
/// \brief Substitute the explicitly-provided template arguments into the
/// given function template according to C++ [temp.arg.explicit].
///
@@ -2613,7 +2632,7 @@ Sema::SubstituteExplicitTemplateArguments(
// Enter a new template instantiation context where we check the
// explicitly-specified template arguments against this function template,
// and then substitute them into the function parameter types.
- SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
+ SmallVector<TemplateArgument, 4> DeducedArgs;
InstantiatingTemplate Inst(*this, Info.getLocation(), FunctionTemplate,
DeducedArgs,
ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution,
@@ -2893,14 +2912,13 @@ static unsigned getPackIndexForParam(Sema &S,
///
/// \param OriginalCallArgs If non-NULL, the original call arguments against
/// which the deduced argument types should be compared.
-Sema::TemplateDeductionResult
-Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned NumExplicitlySpecified,
- FunctionDecl *&Specialization,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
- bool PartialOverloading) {
+Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
+ FunctionTemplateDecl *FunctionTemplate,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ unsigned NumExplicitlySpecified, FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
+ bool PartialOverloading, llvm::function_ref<bool()> CheckNonDependent) {
// Unevaluated SFINAE context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
SFINAETrap Trap(*this);
@@ -2927,6 +2945,18 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
PartialOverloading))
return Result;
+ // C++ [temp.deduct.call]p10: [DR1391]
+ // If deduction succeeds for all parameters that contain
+ // template-parameters that participate in template argument deduction,
+ // and all template arguments are explicitly specified, deduced, or
+ // obtained from default template arguments, remaining parameters are then
+ // compared with the corresponding arguments. For each remaining parameter
+ // P with a type that was non-dependent before substitution of any
+ // explicitly-specified template arguments, if the corresponding argument
+ // A cannot be implicitly converted to P, deduction fails.
+ if (CheckNonDependent())
+ return TDK_NonDependentConversionFailure;
+
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList
= TemplateArgumentList::CreateCopy(Context, Builder);
@@ -3373,12 +3403,19 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
/// \param Info the argument will be updated to provide additional information
/// about template argument deduction.
///
+/// \param CheckNonDependent A callback to invoke to check conversions for
+/// non-dependent parameters, between deduction and substitution, per DR1391.
+/// If this returns true, substitution will be skipped and we return
+/// TDK_NonDependentConversionFailure. The callback is passed the parameter
+/// types (after substituting explicit template arguments).
+///
/// \returns the result of template argument deduction.
Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
FunctionDecl *&Specialization, TemplateDeductionInfo &Info,
- bool PartialOverloading) {
+ bool PartialOverloading,
+ llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent) {
if (FunctionTemplate->isInvalidDecl())
return TDK_Invalid;
@@ -3389,7 +3426,6 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// Template argument deduction is done by comparing each function template
// parameter type (call it P) with the type of the corresponding argument
// of the call (call it A) as described below.
- unsigned CheckArgs = Args.size();
if (Args.size() < Function->getMinRequiredArguments() && !PartialOverloading)
return TDK_TooFewArguments;
else if (TooManyArguments(NumParams, Args.size(), PartialOverloading)) {
@@ -3397,9 +3433,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
= Function->getType()->getAs<FunctionProtoType>();
if (Proto->isTemplateVariadic())
/* Do nothing */;
- else if (Proto->isVariadic())
- CheckArgs = NumParams;
- else
+ else if (!Proto->isVariadic())
return TDK_TooManyArguments;
}
@@ -3409,7 +3443,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
SmallVector<DeducedTemplateArgument, 4> Deduced;
- SmallVector<QualType, 4> ParamTypes;
+ SmallVector<QualType, 8> ParamTypes;
unsigned NumExplicitlySpecified = 0;
if (ExplicitTemplateArgs) {
TemplateDeductionResult Result =
@@ -3429,7 +3463,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
ParamTypes.push_back(Function->getParamDecl(I)->getType());
}
- SmallVector<OriginalCallArg, 4> OriginalCallArgs;
+ SmallVector<OriginalCallArg, 8> OriginalCallArgs;
// Deduce an argument of type ParamType from an expression with index ArgIdx.
auto DeduceCallArgument = [&](QualType ParamType, unsigned ArgIdx) {
@@ -3448,6 +3482,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// Deduce template arguments from the function parameters.
Deduced.resize(TemplateParams->size());
+ SmallVector<QualType, 8> ParamTypesForArgChecking;
for (unsigned ParamIdx = 0, NumParamTypes = ParamTypes.size(), ArgIdx = 0;
ParamIdx != NumParamTypes; ++ParamIdx) {
QualType ParamType = ParamTypes[ParamIdx];
@@ -3456,51 +3491,68 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
dyn_cast<PackExpansionType>(ParamType);
if (!ParamExpansion) {
// Simple case: matching a function parameter to a function argument.
- if (ArgIdx >= CheckArgs)
+ if (ArgIdx >= Args.size())
break;
+ ParamTypesForArgChecking.push_back(ParamType);
if (auto Result = DeduceCallArgument(ParamType, ArgIdx++))
return Result;
continue;
}
+ QualType ParamPattern = ParamExpansion->getPattern();
+ PackDeductionScope PackScope(*this, TemplateParams, Deduced, Info,
+ ParamPattern);
+
// C++0x [temp.deduct.call]p1:
// For a function parameter pack that occurs at the end of the
// parameter-declaration-list, the type A of each remaining argument of
// the call is compared with the type P of the declarator-id of the
// function parameter pack. Each comparison deduces template arguments
// for subsequent positions in the template parameter packs expanded by
- // the function parameter pack. For a function parameter pack that does
- // not occur at the end of the parameter-declaration-list, the type of
- // the parameter pack is a non-deduced context.
- // FIXME: This does not say that subsequent parameters are also non-deduced.
- // See also DR1388 / DR1399, which effectively says we should keep deducing
- // after the pack.
- if (ParamIdx + 1 < NumParamTypes)
- break;
-
- QualType ParamPattern = ParamExpansion->getPattern();
- PackDeductionScope PackScope(*this, TemplateParams, Deduced, Info,
- ParamPattern);
-
- for (; ArgIdx < Args.size(); PackScope.nextPackElement(), ++ArgIdx)
- if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx))
- return Result;
+ // the function parameter pack. When a function parameter pack appears
+ // in a non-deduced context [not at the end of the list], the type of
+ // that parameter pack is never deduced.
+ //
+ // FIXME: The above rule allows the size of the parameter pack to change
+ // after we skip it (in the non-deduced case). That makes no sense, so
+ // we instead notionally deduce the pack against N arguments, where N is
+ // the length of the explicitly-specified pack if it's expanded by the
+ // parameter pack and 0 otherwise, and we treat each deduction as a
+ // non-deduced context.
+ if (ParamIdx + 1 == NumParamTypes) {
+ for (; ArgIdx < Args.size(); PackScope.nextPackElement(), ++ArgIdx) {
+ ParamTypesForArgChecking.push_back(ParamPattern);
+ if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx))
+ return Result;
+ }
+ } else {
+ // If the parameter type contains an explicitly-specified pack that we
+ // could not expand, skip the number of parameters notionally created
+ // by the expansion.
+ Optional<unsigned> NumExpansions = ParamExpansion->getNumExpansions();
+ if (NumExpansions && !PackScope.isPartiallyExpanded()) {
+ for (unsigned I = 0; I != *NumExpansions && ArgIdx < Args.size();
+ ++I, ++ArgIdx) {
+ ParamTypesForArgChecking.push_back(ParamPattern);
+ // FIXME: Should we add OriginalCallArgs for these? What if the
+ // corresponding argument is a list?
+ PackScope.nextPackElement();
+ }
+ }
+ }
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
if (auto Result = PackScope.finish())
return Result;
-
- // After we've matching against a parameter pack, we're done.
- break;
}
- return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
- NumExplicitlySpecified, Specialization,
- Info, &OriginalCallArgs,
- PartialOverloading);
+ return FinishTemplateArgumentDeduction(
+ FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info,
+ &OriginalCallArgs, PartialOverloading,
+ [&]() { return CheckNonDependent(ParamTypesForArgChecking); });
}
QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,
@@ -4230,12 +4282,6 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
return StillUndeduced;
}
-static void
-MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
- bool OnlyDeduced,
- unsigned Level,
- llvm::SmallBitVector &Deduced);
-
/// \brief If this is a non-static member function,
static void
AddImplicitObjectParameterType(ASTContext &Context,
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 160c9f090788..ba4a5b7bc0d7 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2280,16 +2280,18 @@ namespace {
};
}
-bool Sema::InstantiateClassTemplateSpecialization(
- SourceLocation PointOfInstantiation,
+/// Get the instantiation pattern to use to instantiate the definition of a
+/// given ClassTemplateSpecializationDecl (either the pattern of the primary
+/// template or of a partial specialization).
+static CXXRecordDecl *
+getPatternForClassTemplateSpecialization(
+ Sema &S, SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec,
TemplateSpecializationKind TSK, bool Complain) {
- // Perform the actual instantiation on the canonical declaration.
- ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
- ClassTemplateSpec->getCanonicalDecl());
- if (ClassTemplateSpec->isInvalidDecl())
- return true;
-
+ Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec);
+ if (Inst.isInvalid() || Inst.isAlreadyInstantiating())
+ return nullptr;
+
ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
CXXRecordDecl *Pattern = nullptr;
@@ -2309,15 +2311,13 @@ bool Sema::InstantiateClassTemplateSpecialization(
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
TemplateDeductionInfo Info(FailedCandidates.getLocation());
- if (TemplateDeductionResult Result
- = DeduceTemplateArguments(Partial,
- ClassTemplateSpec->getTemplateArgs(),
- Info)) {
+ if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments(
+ Partial, ClassTemplateSpec->getTemplateArgs(), Info)) {
// Store the failed-deduction information for use in diagnostics, later.
// TODO: Actually use the failed-deduction info?
FailedCandidates.addCandidate().set(
DeclAccessPair::make(Template, AS_public), Partial,
- MakeDeductionFailureInfo(Context, Result, Info));
+ MakeDeductionFailureInfo(S.Context, Result, Info));
(void)Result;
} else {
Matched.push_back(PartialSpecMatchResult());
@@ -2347,9 +2347,8 @@ bool Sema::InstantiateClassTemplateSpecialization(
for (SmallVectorImpl<MatchResult>::iterator P = Best + 1,
PEnd = Matched.end();
P != PEnd; ++P) {
- if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
- PointOfInstantiation)
- == P->Partial)
+ if (S.getMoreSpecializedPartialSpecialization(
+ P->Partial, Best->Partial, PointOfInstantiation) == P->Partial)
Best = P;
}
@@ -2360,9 +2359,9 @@ bool Sema::InstantiateClassTemplateSpecialization(
PEnd = Matched.end();
P != PEnd; ++P) {
if (P != Best &&
- getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
- PointOfInstantiation)
- != Best->Partial) {
+ S.getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
+ PointOfInstantiation) !=
+ Best->Partial) {
Ambiguous = true;
break;
}
@@ -2370,20 +2369,20 @@ bool Sema::InstantiateClassTemplateSpecialization(
if (Ambiguous) {
// Partial ordering did not produce a clear winner. Complain.
+ Inst.Clear();
ClassTemplateSpec->setInvalidDecl();
- Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
+ S.Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
<< ClassTemplateSpec;
// Print the matching partial specializations.
for (SmallVectorImpl<MatchResult>::iterator P = Matched.begin(),
PEnd = Matched.end();
P != PEnd; ++P)
- Diag(P->Partial->getLocation(), diag::note_partial_spec_match)
- << getTemplateArgumentBindingsText(
- P->Partial->getTemplateParameters(),
- *P->Args);
+ S.Diag(P->Partial->getLocation(), diag::note_partial_spec_match)
+ << S.getTemplateArgumentBindingsText(
+ P->Partial->getTemplateParameters(), *P->Args);
- return true;
+ return nullptr;
}
}
@@ -2416,13 +2415,27 @@ bool Sema::InstantiateClassTemplateSpecialization(
Pattern = OrigTemplate->getTemplatedDecl();
}
- bool Result = InstantiateClass(PointOfInstantiation, ClassTemplateSpec,
- Pattern,
- getTemplateInstantiationArgs(ClassTemplateSpec),
- TSK,
- Complain);
+ return Pattern;
+}
- return Result;
+bool Sema::InstantiateClassTemplateSpecialization(
+ SourceLocation PointOfInstantiation,
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ TemplateSpecializationKind TSK, bool Complain) {
+ // Perform the actual instantiation on the canonical declaration.
+ ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
+ ClassTemplateSpec->getCanonicalDecl());
+ if (ClassTemplateSpec->isInvalidDecl())
+ return true;
+
+ CXXRecordDecl *Pattern = getPatternForClassTemplateSpecialization(
+ *this, PointOfInstantiation, ClassTemplateSpec, TSK, Complain);
+ if (!Pattern)
+ return true;
+
+ return InstantiateClass(PointOfInstantiation, ClassTemplateSpec, Pattern,
+ getTemplateInstantiationArgs(ClassTemplateSpec), TSK,
+ Complain);
}
/// \brief Instantiates the definitions of all of the member
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f4013b820641..d2a5e5cb5312 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -168,39 +168,59 @@ static void instantiateDependentAlignValueAttr(
Aligned->getSpellingListIndex());
}
-static void instantiateDependentEnableIfAttr(
+static Expr *instantiateDependentFunctionAttrCondition(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
- const EnableIfAttr *A, const Decl *Tmpl, Decl *New) {
+ const Attr *A, Expr *OldCond, const Decl *Tmpl, FunctionDecl *New) {
Expr *Cond = nullptr;
{
- EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
- ExprResult Result = S.SubstExpr(A->getCond(), TemplateArgs);
+ Sema::ContextRAII SwitchContext(S, New);
+ EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
+ ExprResult Result = S.SubstExpr(OldCond, TemplateArgs);
if (Result.isInvalid())
- return;
+ return nullptr;
Cond = Result.getAs<Expr>();
}
if (!Cond->isTypeDependent()) {
ExprResult Converted = S.PerformContextuallyConvertToBool(Cond);
if (Converted.isInvalid())
- return;
+ return nullptr;
Cond = Converted.get();
}
SmallVector<PartialDiagnosticAt, 8> Diags;
- if (A->getCond()->isValueDependent() && !Cond->isValueDependent() &&
- !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(New),
- Diags)) {
- S.Diag(A->getLocation(), diag::err_enable_if_never_constant_expr);
- for (int I = 0, N = Diags.size(); I != N; ++I)
- S.Diag(Diags[I].first, Diags[I].second);
- return;
+ if (OldCond->isValueDependent() && !Cond->isValueDependent() &&
+ !Expr::isPotentialConstantExprUnevaluated(Cond, New, Diags)) {
+ S.Diag(A->getLocation(), diag::err_attr_cond_never_constant_expr) << A;
+ for (const auto &P : Diags)
+ S.Diag(P.first, P.second);
+ return nullptr;
}
+ return Cond;
+}
- EnableIfAttr *EIA = new (S.getASTContext())
- EnableIfAttr(A->getLocation(), S.getASTContext(), Cond,
- A->getMessage(),
- A->getSpellingListIndex());
- New->addAttr(EIA);
+static void instantiateDependentEnableIfAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const EnableIfAttr *EIA, const Decl *Tmpl, FunctionDecl *New) {
+ Expr *Cond = instantiateDependentFunctionAttrCondition(
+ S, TemplateArgs, EIA, EIA->getCond(), Tmpl, New);
+
+ if (Cond)
+ New->addAttr(new (S.getASTContext()) EnableIfAttr(
+ EIA->getLocation(), S.getASTContext(), Cond, EIA->getMessage(),
+ EIA->getSpellingListIndex()));
+}
+
+static void instantiateDependentDiagnoseIfAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const DiagnoseIfAttr *DIA, const Decl *Tmpl, FunctionDecl *New) {
+ Expr *Cond = instantiateDependentFunctionAttrCondition(
+ S, TemplateArgs, DIA, DIA->getCond(), Tmpl, New);
+
+ if (Cond)
+ New->addAttr(new (S.getASTContext()) DiagnoseIfAttr(
+ DIA->getLocation(), S.getASTContext(), Cond, DIA->getMessage(),
+ DIA->getDiagnosticType(), DIA->getArgDependent(), New,
+ DIA->getSpellingListIndex()));
}
// Constructs and adds to New a new instance of CUDALaunchBoundsAttr using
@@ -334,7 +354,13 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) {
instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl,
- New);
+ cast<FunctionDecl>(New));
+ continue;
+ }
+
+ if (const auto *DiagnoseIf = dyn_cast<DiagnoseIfAttr>(TmplAttr)) {
+ instantiateDependentDiagnoseIfAttr(*this, TemplateArgs, DiagnoseIf, Tmpl,
+ cast<FunctionDecl>(New));
continue;
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 2a5eda436f09..39e842db2baa 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -4654,17 +4654,6 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
// If we're emitting a module, write out the submodule information.
if (WritingModule)
WriteSubmodules(WritingModule);
- else if (!getLangOpts().CurrentModule.empty()) {
- // If we're building a PCH in the implementation of a module, we may need
- // the description of the current module.
- //
- // FIXME: We may need other modules that we did not load from an AST file,
- // such as if a module declares a 'conflicts' on a different module.
- Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule(
- getLangOpts().CurrentModule);
- if (M && !M->IsFromModuleFile)
- WriteSubmodules(M);
- }
Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes);
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 41415f0376c0..05505ec38600 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -39,6 +39,7 @@ add_clang_library(clangStaticAnalyzerCheckers
GenericTaintChecker.cpp
GTestChecker.cpp
IdenticalExprChecker.cpp
+ IteratorPastEndChecker.cpp
IvarInvalidationChecker.cpp
LLVMConventionsChecker.cpp
LocalizationChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp b/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp
new file mode 100644
index 000000000000..531054aa7887
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp
@@ -0,0 +1,842 @@
+//===-- IteratorPastEndChecker.cpp --------------------------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a checker for using iterators outside their range (past end). Usage
+// means here dereferencing, incrementing etc.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+#include <utility>
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+struct IteratorPosition {
+private:
+ enum Kind { InRange, OutofRange } K;
+ IteratorPosition(Kind InK) : K(InK) {}
+
+public:
+ bool isInRange() const { return K == InRange; }
+ bool isOutofRange() const { return K == OutofRange; }
+
+ static IteratorPosition getInRange() { return IteratorPosition(InRange); }
+ static IteratorPosition getOutofRange() {
+ return IteratorPosition(OutofRange);
+ }
+
+ bool operator==(const IteratorPosition &X) const { return K == X.K; }
+ bool operator!=(const IteratorPosition &X) const { return K != X.K; }
+ void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); }
+};
+
+typedef llvm::PointerUnion<const MemRegion *, SymbolRef> RegionOrSymbol;
+
+struct IteratorComparison {
+private:
+ RegionOrSymbol Left, Right;
+ bool Equality;
+
+public:
+ IteratorComparison(RegionOrSymbol L, RegionOrSymbol R, bool Eq)
+ : Left(L), Right(R), Equality(Eq) {}
+
+ RegionOrSymbol getLeft() const { return Left; }
+ RegionOrSymbol getRight() const { return Right; }
+ bool isEquality() const { return Equality; }
+ bool operator==(const IteratorComparison &X) const {
+ return Left == X.Left && Right == X.Right && Equality == X.Equality;
+ }
+ bool operator!=(const IteratorComparison &X) const {
+ return Left != X.Left || Right != X.Right || Equality != X.Equality;
+ }
+ void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Equality); }
+};
+
+class IteratorPastEndChecker
+ : public Checker<
+ check::PreCall, check::PostCall, check::PreStmt<CXXOperatorCallExpr>,
+ check::PostStmt<CXXConstructExpr>, check::PostStmt<DeclStmt>,
+ check::PostStmt<MaterializeTemporaryExpr>, check::BeginFunction,
+ check::DeadSymbols, eval::Assume, eval::Call> {
+ mutable IdentifierInfo *II_find = nullptr,
+ *II_find_end = nullptr, *II_find_first_of = nullptr,
+ *II_find_if = nullptr, *II_find_if_not = nullptr,
+ *II_lower_bound = nullptr, *II_upper_bound = nullptr,
+ *II_search = nullptr, *II_search_n = nullptr;
+
+ std::unique_ptr<BugType> PastEndBugType;
+
+ void handleComparison(CheckerContext &C, const SVal &RetVal, const SVal &LVal,
+ const SVal &RVal, OverloadedOperatorKind Op) const;
+ void handleAccess(CheckerContext &C, const SVal &Val) const;
+ void handleDecrement(CheckerContext &C, const SVal &Val) const;
+ void handleEnd(CheckerContext &C, const SVal &RetVal) const;
+
+ bool evalFind(CheckerContext &C, const CallExpr *CE) const;
+ bool evalFindEnd(CheckerContext &C, const CallExpr *CE) const;
+ bool evalFindFirstOf(CheckerContext &C, const CallExpr *CE) const;
+ bool evalFindIf(CheckerContext &C, const CallExpr *CE) const;
+ bool evalFindIfNot(CheckerContext &C, const CallExpr *CE) const;
+ bool evalLowerBound(CheckerContext &C, const CallExpr *CE) const;
+ bool evalUpperBound(CheckerContext &C, const CallExpr *CE) const;
+ bool evalSearch(CheckerContext &C, const CallExpr *CE) const;
+ bool evalSearchN(CheckerContext &C, const CallExpr *CE) const;
+ void Find(CheckerContext &C, const CallExpr *CE) const;
+
+ void reportPastEndBug(const StringRef &Message, const SVal &Val,
+ CheckerContext &C, ExplodedNode *ErrNode) const;
+ void initIdentifiers(ASTContext &Ctx) const;
+
+public:
+ IteratorPastEndChecker();
+
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkPreStmt(const CXXOperatorCallExpr *COCE, CheckerContext &C) const;
+ void checkBeginFunction(CheckerContext &C) const;
+ void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
+ void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
+ void checkPostStmt(const MaterializeTemporaryExpr *MTE,
+ CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
+ ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
+ bool Assumption) const;
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+};
+}
+
+REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition)
+REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *,
+ IteratorPosition)
+
+REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap, const SymExpr *,
+ IteratorComparison)
+
+#define INIT_ID(Id) \
+ if (!II_##Id) \
+ II_##Id = &Ctx.Idents.get(#Id)
+
+namespace {
+
+bool isIteratorType(const QualType &Type);
+bool isIterator(const CXXRecordDecl *CRD);
+bool isEndCall(const FunctionDecl *Func);
+bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
+bool isAccessOperator(OverloadedOperatorKind OK);
+bool isDecrementOperator(OverloadedOperatorKind OK);
+BinaryOperator::Opcode getOpcode(const SymExpr *SE);
+const RegionOrSymbol getRegionOrSymbol(const SVal &Val);
+const ProgramStateRef processComparison(ProgramStateRef State,
+ RegionOrSymbol LVal,
+ RegionOrSymbol RVal, bool Equal);
+const ProgramStateRef saveComparison(ProgramStateRef State,
+ const SymExpr *Condition, const SVal &LVal,
+ const SVal &RVal, bool Eq);
+const IteratorComparison *loadComparison(ProgramStateRef State,
+ const SymExpr *Condition);
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ const SVal &Val);
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym);
+ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
+ IteratorPosition Pos);
+ProgramStateRef setIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ IteratorPosition Pos);
+ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ IteratorPosition Pos, bool Equal);
+bool contradictingIteratorPositions(IteratorPosition Pos1,
+ IteratorPosition Pos2, bool Equal);
+}
+
+IteratorPastEndChecker::IteratorPastEndChecker() {
+ PastEndBugType.reset(
+ new BugType(this, "Iterator Past End", "Misuse of STL APIs"));
+ PastEndBugType->setSuppressOnSink(true);
+}
+
+void IteratorPastEndChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ // Check for access past end
+ const auto *Func = Call.getDecl()->getAsFunction();
+ if (!Func)
+ return;
+ if (Func->isOverloadedOperator()) {
+ if (isAccessOperator(Func->getOverloadedOperator())) {
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ handleAccess(C, InstCall->getCXXThisVal());
+ } else {
+ handleAccess(C, Call.getArgSVal(0));
+ }
+ }
+ }
+}
+
+void IteratorPastEndChecker::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ // Record end() iterators, iterator decrementation and comparison
+ const auto *Func = Call.getDecl()->getAsFunction();
+ if (!Func)
+ return;
+ if (Func->isOverloadedOperator()) {
+ const auto Op = Func->getOverloadedOperator();
+ if (isSimpleComparisonOperator(Op)) {
+ if (Func->isCXXInstanceMember()) {
+ const auto &InstCall = static_cast<const CXXInstanceCall &>(Call);
+ handleComparison(C, InstCall.getReturnValue(), InstCall.getCXXThisVal(),
+ InstCall.getArgSVal(0), Op);
+ } else {
+ handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0),
+ Call.getArgSVal(1), Op);
+ }
+ } else if (isDecrementOperator(Func->getOverloadedOperator())) {
+ if (Func->isCXXInstanceMember()) {
+ const auto &InstCall = static_cast<const CXXInstanceCall &>(Call);
+ handleDecrement(C, InstCall.getCXXThisVal());
+ } else {
+ handleDecrement(C, Call.getArgSVal(0));
+ }
+ }
+ } else if (Func->isCXXInstanceMember()) {
+ if (!isEndCall(Func))
+ return;
+ if (!isIteratorType(Call.getResultType()))
+ return;
+ handleEnd(C, Call.getReturnValue());
+ }
+}
+
+void IteratorPastEndChecker::checkPreStmt(const CXXOperatorCallExpr *COCE,
+ CheckerContext &C) const {
+ const auto *ThisExpr = COCE->getArg(0);
+
+ auto State = C.getState();
+ const auto *LCtx = C.getPredecessor()->getLocationContext();
+
+ const auto CurrentThis = State->getSVal(ThisExpr, LCtx);
+ if (const auto *Reg = CurrentThis.getAsRegion()) {
+ if (!Reg->getAs<CXXTempObjectRegion>())
+ return;
+ const auto OldState = C.getPredecessor()->getFirstPred()->getState();
+ const auto OldThis = OldState->getSVal(ThisExpr, LCtx);
+ const auto *Pos = getIteratorPosition(OldState, OldThis);
+ if (!Pos)
+ return;
+ State = setIteratorPosition(State, CurrentThis, *Pos);
+ C.addTransition(State);
+ }
+}
+
+void IteratorPastEndChecker::checkBeginFunction(CheckerContext &C) const {
+ // Copy state of iterator arguments to iterator parameters
+ auto State = C.getState();
+ const auto *LCtx = C.getLocationContext();
+
+ const auto *Site = cast<StackFrameContext>(LCtx)->getCallSite();
+ if (!Site)
+ return;
+
+ const auto *FD = dyn_cast<FunctionDecl>(LCtx->getDecl());
+ if (!FD)
+ return;
+
+ const auto *CE = dyn_cast<CallExpr>(Site);
+ if (!CE)
+ return;
+
+ bool Change = false;
+ int idx = 0;
+ for (const auto P : FD->parameters()) {
+ auto Param = State->getLValue(P, LCtx);
+ auto Arg = State->getSVal(CE->getArg(idx++), LCtx->getParent());
+ const auto *Pos = getIteratorPosition(State, Arg);
+ if (!Pos)
+ continue;
+ State = setIteratorPosition(State, Param, *Pos);
+ Change = true;
+ }
+ if (Change) {
+ C.addTransition(State);
+ }
+}
+
+void IteratorPastEndChecker::checkPostStmt(const CXXConstructExpr *CCE,
+ CheckerContext &C) const {
+ // Transfer iterator state in case of copy or move by constructor
+ const auto *ctr = CCE->getConstructor();
+ if (!ctr->isCopyOrMoveConstructor())
+ return;
+ const auto *RHSExpr = CCE->getArg(0);
+
+ auto State = C.getState();
+ const auto *LCtx = C.getLocationContext();
+
+ const auto RetVal = State->getSVal(CCE, LCtx);
+
+ const auto RHSVal = State->getSVal(RHSExpr, LCtx);
+ const auto *RHSPos = getIteratorPosition(State, RHSVal);
+ if (!RHSPos)
+ return;
+ State = setIteratorPosition(State, RetVal, *RHSPos);
+ C.addTransition(State);
+}
+
+void IteratorPastEndChecker::checkPostStmt(const DeclStmt *DS,
+ CheckerContext &C) const {
+ // Transfer iterator state to new variable declaration
+ for (const auto *D : DS->decls()) {
+ const auto *VD = dyn_cast<VarDecl>(D);
+ if (!VD || !VD->hasInit())
+ continue;
+
+ auto State = C.getState();
+ const auto *LCtx = C.getPredecessor()->getLocationContext();
+ const auto *Pos =
+ getIteratorPosition(State, State->getSVal(VD->getInit(), LCtx));
+ if (!Pos)
+ continue;
+ State = setIteratorPosition(State, State->getLValue(VD, LCtx), *Pos);
+ C.addTransition(State);
+ }
+}
+
+void IteratorPastEndChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE,
+ CheckerContext &C) const {
+ /* Transfer iterator state for to temporary objects */
+ auto State = C.getState();
+ const auto *LCtx = C.getPredecessor()->getLocationContext();
+ const auto *Pos =
+ getIteratorPosition(State, State->getSVal(MTE->GetTemporaryExpr(), LCtx));
+ if (!Pos)
+ return;
+ State = setIteratorPosition(State, State->getSVal(MTE, LCtx), *Pos);
+ C.addTransition(State);
+}
+
+void IteratorPastEndChecker::checkDeadSymbols(SymbolReaper &SR,
+ CheckerContext &C) const {
+ auto State = C.getState();
+
+ auto RegionMap = State->get<IteratorRegionMap>();
+ for (const auto Reg : RegionMap) {
+ if (!SR.isLiveRegion(Reg.first)) {
+ State = State->remove<IteratorRegionMap>(Reg.first);
+ }
+ }
+
+ auto SymbolMap = State->get<IteratorSymbolMap>();
+ for (const auto Sym : SymbolMap) {
+ if (SR.isDead(Sym.first)) {
+ State = State->remove<IteratorSymbolMap>(Sym.first);
+ }
+ }
+
+ auto ComparisonMap = State->get<IteratorComparisonMap>();
+ for (const auto Comp : ComparisonMap) {
+ if (SR.isDead(Comp.first)) {
+ State = State->remove<IteratorComparisonMap>(Comp.first);
+ }
+ }
+}
+
+ProgramStateRef IteratorPastEndChecker::evalAssume(ProgramStateRef State,
+ SVal Cond,
+ bool Assumption) const {
+ // Load recorded comparison and transfer iterator state between sides
+ // according to comparison operator and assumption
+ const auto *SE = Cond.getAsSymExpr();
+ if (!SE)
+ return State;
+
+ auto Opc = getOpcode(SE);
+ if (Opc != BO_EQ && Opc != BO_NE)
+ return State;
+
+ bool Negated = false;
+ const auto *Comp = loadComparison(State, SE);
+ if (!Comp) {
+ // Try negated comparison, which is a SymExpr to 0 integer comparison
+ const auto *SIE = dyn_cast<SymIntExpr>(SE);
+ if (!SIE)
+ return State;
+
+ if (SIE->getRHS() != 0)
+ return State;
+
+ SE = SIE->getLHS();
+ Negated = SIE->getOpcode() == BO_EQ; // Equal to zero means negation
+ Opc = getOpcode(SE);
+ if (Opc != BO_EQ && Opc != BO_NE)
+ return State;
+
+ Comp = loadComparison(State, SE);
+ if (!Comp)
+ return State;
+ }
+
+ return processComparison(State, Comp->getLeft(), Comp->getRight(),
+ (Comp->isEquality() == Assumption) != Negated);
+}
+
+// FIXME: Evaluation of these STL calls should be moved to StdCLibraryFunctions
+// checker (see patch r284960) or another similar checker for C++ STL
+// functions (e.g. StdCXXLibraryFunctions or StdCppLibraryFunctions).
+bool IteratorPastEndChecker::evalCall(const CallExpr *CE,
+ CheckerContext &C) const {
+ const FunctionDecl *FD = C.getCalleeDecl(CE);
+ if (!FD)
+ return false;
+
+ ASTContext &Ctx = C.getASTContext();
+ initIdentifiers(Ctx);
+
+ if (FD->getKind() == Decl::Function) {
+ if (FD->isInStdNamespace()) {
+ if (FD->getIdentifier() == II_find) {
+ return evalFind(C, CE);
+ } else if (FD->getIdentifier() == II_find_end) {
+ return evalFindEnd(C, CE);
+ } else if (FD->getIdentifier() == II_find_first_of) {
+ return evalFindFirstOf(C, CE);
+ } else if (FD->getIdentifier() == II_find_if) {
+ return evalFindIf(C, CE);
+ } else if (FD->getIdentifier() == II_find_if) {
+ return evalFindIf(C, CE);
+ } else if (FD->getIdentifier() == II_find_if_not) {
+ return evalFindIfNot(C, CE);
+ } else if (FD->getIdentifier() == II_upper_bound) {
+ return evalUpperBound(C, CE);
+ } else if (FD->getIdentifier() == II_lower_bound) {
+ return evalLowerBound(C, CE);
+ } else if (FD->getIdentifier() == II_search) {
+ return evalSearch(C, CE);
+ } else if (FD->getIdentifier() == II_search_n) {
+ return evalSearchN(C, CE);
+ }
+ }
+ }
+
+ return false;
+}
+
+void IteratorPastEndChecker::handleComparison(CheckerContext &C,
+ const SVal &RetVal,
+ const SVal &LVal,
+ const SVal &RVal,
+ OverloadedOperatorKind Op) const {
+ // Record the operands and the operator of the comparison for the next
+ // evalAssume, if the result is a symbolic expression. If it is a concrete
+ // value (only one branch is possible), then transfer the state between
+ // the operands according to the operator and the result
+ auto State = C.getState();
+ if (const auto *Condition = RetVal.getAsSymbolicExpression()) {
+ const auto *LPos = getIteratorPosition(State, LVal);
+ const auto *RPos = getIteratorPosition(State, RVal);
+ if (!LPos && !RPos)
+ return;
+ State = saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual);
+ C.addTransition(State);
+ } else if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
+ if ((State = processComparison(
+ State, getRegionOrSymbol(LVal), getRegionOrSymbol(RVal),
+ (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) {
+ C.addTransition(State);
+ } else {
+ C.generateSink(State, C.getPredecessor());
+ }
+ }
+}
+
+void IteratorPastEndChecker::handleAccess(CheckerContext &C,
+ const SVal &Val) const {
+ auto State = C.getState();
+ const auto *Pos = getIteratorPosition(State, Val);
+ if (Pos && Pos->isOutofRange()) {
+ auto *N = C.generateNonFatalErrorNode(State);
+ if (!N) {
+ return;
+ }
+ reportPastEndBug("Iterator accessed past its end.", Val, C, N);
+ }
+}
+
+void IteratorPastEndChecker::handleDecrement(CheckerContext &C,
+ const SVal &Val) const {
+ auto State = C.getState();
+ const auto *Pos = getIteratorPosition(State, Val);
+ if (Pos && Pos->isOutofRange()) {
+ State = setIteratorPosition(State, Val, IteratorPosition::getInRange());
+ // FIXME: We could also check for iterators ahead of their beginnig in the
+ // future, but currently we do not care for such errors. We also
+ // assume that the iterator is not past its end by more then one
+ // position.
+ C.addTransition(State);
+ }
+}
+
+void IteratorPastEndChecker::handleEnd(CheckerContext &C,
+ const SVal &RetVal) const {
+ auto State = C.getState();
+ State = setIteratorPosition(State, RetVal, IteratorPosition::getOutofRange());
+ C.addTransition(State);
+}
+
+bool IteratorPastEndChecker::evalFind(CheckerContext &C,
+ const CallExpr *CE) const {
+ if (CE->getNumArgs() == 3 && isIteratorType(CE->getArg(0)->getType()) &&
+ isIteratorType(CE->getArg(1)->getType())) {
+ Find(C, CE);
+ return true;
+ }
+ return false;
+}
+
+bool IteratorPastEndChecker::evalFindEnd(CheckerContext &C,
+ const CallExpr *CE) const {
+ if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
+ isIteratorType(CE->getArg(0)->getType()) &&
+ isIteratorType(CE->getArg(1)->getType()) &&
+ isIteratorType(CE->getArg(2)->getType()) &&
+ isIteratorType(CE->getArg(3)->getType())) {
+ Find(C, CE);
+ return true;
+ }
+ return false;
+}
+
+bool IteratorPastEndChecker::evalFindFirstOf(CheckerContext &C,
+ const CallExpr *CE) const {
+ if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
+ isIteratorType(CE->getArg(0)->getType()) &&
+ isIteratorType(CE->getArg(1)->getType()) &&
+ isIteratorType(CE->getArg(2)->getType()) &&
+ isIteratorType(CE->getArg(3)->getType())) {
+ Find(C, CE);
+ return true;
+ }
+ return false;
+}
+
+bool IteratorPastEndChecker::evalFindIf(CheckerContext &C,
+ const CallExpr *CE) const {
+ if (CE->getNumArgs() == 3 && isIteratorType(CE->getArg(0)->getType()) &&
+ isIteratorType(CE->getArg(1)->getType())) {
+ Find(C, CE);
+ return true;
+ }
+ return false;
+}
+
+bool IteratorPastEndChecker::evalFindIfNot(CheckerContext &C,
+ const CallExpr *CE) const {
+ if (CE->getNumArgs() == 3 && isIteratorType(CE->getArg(0)->getType()) &&
+ isIteratorType(CE->getArg(1)->getType())) {
+ Find(C, CE);
+ return true;
+ }
+ return false;
+}
+
+bool IteratorPastEndChecker::evalLowerBound(CheckerContext &C,
+ const CallExpr *CE) const {
+ if ((CE->getNumArgs() == 3 || CE->getNumArgs() == 4) &&
+ isIteratorType(CE->getArg(0)->getType()) &&
+ isIteratorType(CE->getArg(1)->getType())) {
+ Find(C, CE);
+ return true;
+ }
+ return false;
+}
+
+bool IteratorPastEndChecker::evalUpperBound(CheckerContext &C,
+ const CallExpr *CE) const {
+ if ((CE->getNumArgs() == 3 || CE->getNumArgs() == 4) &&
+ isIteratorType(CE->getArg(0)->getType()) &&
+ isIteratorType(CE->getArg(1)->getType())) {
+ Find(C, CE);
+ return true;
+ }
+ return false;
+}
+
+bool IteratorPastEndChecker::evalSearch(CheckerContext &C,
+ const CallExpr *CE) const {
+ if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
+ isIteratorType(CE->getArg(0)->getType()) &&
+ isIteratorType(CE->getArg(1)->getType()) &&
+ isIteratorType(CE->getArg(2)->getType()) &&
+ isIteratorType(CE->getArg(3)->getType())) {
+ Find(C, CE);
+ return true;
+ }
+ return false;
+}
+
+bool IteratorPastEndChecker::evalSearchN(CheckerContext &C,
+ const CallExpr *CE) const {
+ if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
+ isIteratorType(CE->getArg(0)->getType()) &&
+ isIteratorType(CE->getArg(1)->getType())) {
+ Find(C, CE);
+ return true;
+ }
+ return false;
+}
+
+void IteratorPastEndChecker::Find(CheckerContext &C, const CallExpr *CE) const {
+ auto state = C.getState();
+ auto &svalBuilder = C.getSValBuilder();
+ const auto *LCtx = C.getLocationContext();
+
+ auto RetVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
+ auto SecondParam = state->getSVal(CE->getArg(1), LCtx);
+
+ auto stateFound = state->BindExpr(CE, LCtx, RetVal);
+ auto stateNotFound = state->BindExpr(CE, LCtx, SecondParam);
+
+ C.addTransition(stateFound);
+ C.addTransition(stateNotFound);
+}
+
+void IteratorPastEndChecker::reportPastEndBug(const StringRef &Message,
+ const SVal &Val,
+ CheckerContext &C,
+ ExplodedNode *ErrNode) const {
+ auto R = llvm::make_unique<BugReport>(*PastEndBugType, Message, ErrNode);
+ R->markInteresting(Val);
+ C.emitReport(std::move(R));
+}
+
+void IteratorPastEndChecker::initIdentifiers(ASTContext &Ctx) const {
+ INIT_ID(find);
+ INIT_ID(find_end);
+ INIT_ID(find_first_of);
+ INIT_ID(find_if);
+ INIT_ID(find_if_not);
+ INIT_ID(lower_bound);
+ INIT_ID(upper_bound);
+ INIT_ID(search);
+ INIT_ID(search_n);
+}
+
+namespace {
+
+bool isIteratorType(const QualType &Type) {
+ if (Type->isPointerType())
+ return true;
+
+ const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
+ return isIterator(CRD);
+}
+
+bool isIterator(const CXXRecordDecl *CRD) {
+ if (!CRD)
+ return false;
+
+ const auto Name = CRD->getName();
+ if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
+ Name.endswith_lower("it")))
+ return false;
+
+ bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
+ HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
+ for (const auto *Method : CRD->methods()) {
+ if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
+ if (Ctor->isCopyConstructor()) {
+ HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
+ }
+ continue;
+ }
+ if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
+ HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
+ continue;
+ }
+ if (Method->isCopyAssignmentOperator()) {
+ HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
+ continue;
+ }
+ if (!Method->isOverloadedOperator())
+ continue;
+ const auto OPK = Method->getOverloadedOperator();
+ if (OPK == OO_PlusPlus) {
+ HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
+ HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
+ continue;
+ }
+ if (OPK == OO_Star) {
+ HasDerefOp = (Method->getNumParams() == 0);
+ continue;
+ }
+ }
+
+ return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
+ HasPostIncrOp && HasDerefOp;
+}
+
+bool isEndCall(const FunctionDecl *Func) {
+ const auto *IdInfo = Func->getIdentifier();
+ if (!IdInfo)
+ return false;
+ return IdInfo->getName().endswith_lower("end");
+}
+
+bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
+ return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
+}
+
+bool isAccessOperator(OverloadedOperatorKind OK) {
+ return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
+ OK == OO_Plus || OK == OO_PlusEqual || OK == OO_PlusPlus ||
+ OK == OO_Subscript;
+}
+
+bool isDecrementOperator(OverloadedOperatorKind OK) {
+ return OK == OO_MinusEqual || OK == OO_MinusMinus;
+}
+
+BinaryOperator::Opcode getOpcode(const SymExpr *SE) {
+ if (const auto *BSE = dyn_cast<BinarySymExpr>(SE)) {
+ return BSE->getOpcode();
+ } else if (const auto *SC = dyn_cast<SymbolConjured>(SE)) {
+ const auto *COE = dyn_cast<CXXOperatorCallExpr>(SC->getStmt());
+ if (!COE)
+ return BO_Comma; // Extremal value, neither EQ nor NE
+ if (COE->getOperator() == OO_EqualEqual) {
+ return BO_EQ;
+ } else if (COE->getOperator() == OO_ExclaimEqual) {
+ return BO_NE;
+ }
+ return BO_Comma; // Extremal value, neither EQ nor NE
+ }
+ return BO_Comma; // Extremal value, neither EQ nor NE
+}
+
+const RegionOrSymbol getRegionOrSymbol(const SVal &Val) {
+ if (const auto Reg = Val.getAsRegion()) {
+ return Reg;
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return Sym;
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return LCVal->getRegion();
+ }
+ return RegionOrSymbol();
+}
+
+const ProgramStateRef processComparison(ProgramStateRef State,
+ RegionOrSymbol LVal,
+ RegionOrSymbol RVal, bool Equal) {
+ const auto *LPos = getIteratorPosition(State, LVal);
+ const auto *RPos = getIteratorPosition(State, RVal);
+ if (LPos && !RPos) {
+ State = adjustIteratorPosition(State, RVal, *LPos, Equal);
+ } else if (!LPos && RPos) {
+ State = adjustIteratorPosition(State, LVal, *RPos, Equal);
+ } else if (LPos && RPos) {
+ if (contradictingIteratorPositions(*LPos, *RPos, Equal)) {
+ return nullptr;
+ }
+ }
+ return State;
+}
+
+const ProgramStateRef saveComparison(ProgramStateRef State,
+ const SymExpr *Condition, const SVal &LVal,
+ const SVal &RVal, bool Eq) {
+ const auto Left = getRegionOrSymbol(LVal);
+ const auto Right = getRegionOrSymbol(RVal);
+ if (!Left || !Right)
+ return State;
+ return State->set<IteratorComparisonMap>(Condition,
+ IteratorComparison(Left, Right, Eq));
+}
+
+const IteratorComparison *loadComparison(ProgramStateRef State,
+ const SymExpr *Condition) {
+ return State->get<IteratorComparisonMap>(Condition);
+}
+
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ const SVal &Val) {
+ if (const auto Reg = Val.getAsRegion()) {
+ return State->get<IteratorRegionMap>(Reg);
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return State->get<IteratorSymbolMap>(Sym);
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return State->get<IteratorRegionMap>(LCVal->getRegion());
+ }
+ return nullptr;
+}
+
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym) {
+ if (RegOrSym.is<const MemRegion *>()) {
+ return State->get<IteratorRegionMap>(RegOrSym.get<const MemRegion *>());
+ } else if (RegOrSym.is<SymbolRef>()) {
+ return State->get<IteratorSymbolMap>(RegOrSym.get<SymbolRef>());
+ }
+ return nullptr;
+}
+
+ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
+ IteratorPosition Pos) {
+ if (const auto Reg = Val.getAsRegion()) {
+ return State->set<IteratorRegionMap>(Reg, Pos);
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return State->set<IteratorSymbolMap>(Sym, Pos);
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
+ }
+ return nullptr;
+}
+
+ProgramStateRef setIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ IteratorPosition Pos) {
+ if (RegOrSym.is<const MemRegion *>()) {
+ return State->set<IteratorRegionMap>(RegOrSym.get<const MemRegion *>(),
+ Pos);
+ } else if (RegOrSym.is<SymbolRef>()) {
+ return State->set<IteratorSymbolMap>(RegOrSym.get<SymbolRef>(), Pos);
+ }
+ return nullptr;
+}
+
+ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ IteratorPosition Pos, bool Equal) {
+
+ if ((Pos.isInRange() && Equal) || (Pos.isOutofRange() && !Equal)) {
+ return setIteratorPosition(State, RegOrSym, IteratorPosition::getInRange());
+ } else if (Pos.isOutofRange() && Equal) {
+ return setIteratorPosition(State, RegOrSym,
+ IteratorPosition::getOutofRange());
+ } else {
+ return State;
+ }
+}
+
+bool contradictingIteratorPositions(IteratorPosition Pos1,
+ IteratorPosition Pos2, bool Equal) {
+ return ((Pos1 != Pos2) && Equal) ||
+ ((Pos1.isOutofRange() && Pos2.isOutofRange()) && !Equal);
+}
+}
+
+void ento::registerIteratorPastEndChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<IteratorPastEndChecker>();
+}
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 707168b4de0a..7e7e329dc4d7 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1248,7 +1248,14 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Expr::MaterializeTemporaryExprClass: {
Bldr.takeNodes(Pred);
const MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(S);
- CreateCXXTemporaryObject(MTE, Pred, Dst);
+ ExplodedNodeSet dstPrevisit;
+ getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, MTE, *this);
+ ExplodedNodeSet dstExpr;
+ for (ExplodedNodeSet::iterator i = dstPrevisit.begin(),
+ e = dstPrevisit.end(); i != e ; ++i) {
+ CreateCXXTemporaryObject(MTE, *i, dstExpr);
+ }
+ getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, MTE, *this);
Bldr.addNodes(Dst);
break;
}
diff --git a/test/Analysis/Inputs/system-header-simulator-cxx.h b/test/Analysis/Inputs/system-header-simulator-cxx.h
index 04f1000dbc3f..005e7f57af6f 100644
--- a/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ b/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -10,6 +10,29 @@ typedef unsigned char uint8_t;
typedef __typeof__(sizeof(int)) size_t;
void *memmove(void *s1, const void *s2, size_t n);
+template <typename T, typename Ptr, typename Ref> struct __iterator {
+ typedef __iterator<T, T *, T &> iterator;
+ typedef __iterator<T, const T *, const T &> const_iterator;
+
+ __iterator(const Ptr p) : ptr(p) {}
+
+ __iterator<T, Ptr, Ref> operator++() { return *this; }
+ __iterator<T, Ptr, Ref> operator++(int) { return *this; }
+ __iterator<T, Ptr, Ref> operator--() { return *this; }
+ __iterator<T, Ptr, Ref> operator--(int) { return *this; }
+ Ref operator*() const { return *ptr; }
+ Ptr operator->() const { return *ptr; }
+
+ bool operator==(const iterator &rhs) const { return ptr == rhs.ptr; }
+ bool operator==(const const_iterator &rhs) const { return ptr == rhs.ptr; }
+
+ bool operator!=(const iterator &rhs) const { return ptr != rhs.ptr; }
+ bool operator!=(const const_iterator &rhs) const { return ptr != rhs.ptr; }
+
+private:
+ Ptr ptr;
+};
+
namespace std {
template <class T1, class T2>
struct pair {
@@ -27,6 +50,9 @@ namespace std {
template<typename T>
class vector {
+ typedef __iterator<T, T *, T &> iterator;
+ typedef __iterator<T, const T *, const T &> const_iterator;
+
T *_start;
T *_finish;
T *_end_of_storage;
@@ -49,11 +75,10 @@ namespace std {
return _start[n];
}
- T *begin() { return _start; }
- const T *begin() const { return _start; }
-
- T *end() { return _finish; }
- const T *end() const { return _finish; }
+ iterator begin() { return iterator(_start); }
+ const_iterator begin() const { return const_iterator(_start); }
+ iterator end() { return iterator(_finish); }
+ const_iterator end() const { return const_iterator(_finish); }
};
class exception {
@@ -223,6 +248,35 @@ namespace std {
return __copy_backward(II, IE, OI);
}
+ template <class InputIterator, class T>
+ InputIterator find(InputIterator first, InputIterator last, const T &val);
+ template <class ForwardIterator1, class ForwardIterator2>
+ ForwardIterator1 find_end(ForwardIterator1 first1, ForwardIterator1 last1,
+ ForwardIterator2 first2, ForwardIterator2 last2);
+ template <class ForwardIterator1, class ForwardIterator2>
+ ForwardIterator1 find_first_of(ForwardIterator1 first1,
+ ForwardIterator1 last1,
+ ForwardIterator2 first2,
+ ForwardIterator2 last2);
+ template <class InputIterator, class UnaryPredicate>
+ InputIterator find_if(InputIterator first, InputIterator last,
+ UnaryPredicate pred);
+ template <class InputIterator, class UnaryPredicate>
+ InputIterator find_if_not(InputIterator first, InputIterator last,
+ UnaryPredicate pred);
+ template <class InputIterator, class T>
+ InputIterator lower_bound(InputIterator first, InputIterator last,
+ const T &val);
+ template <class InputIterator, class T>
+ InputIterator upper_bound(InputIterator first, InputIterator last,
+ const T &val);
+ template <class ForwardIterator1, class ForwardIterator2>
+ ForwardIterator1 search(ForwardIterator1 first1, ForwardIterator1 last1,
+ ForwardIterator2 first2, ForwardIterator2 last2);
+ template <class ForwardIterator1, class ForwardIterator2>
+ ForwardIterator1 search_n(ForwardIterator1 first1, ForwardIterator1 last1,
+ ForwardIterator2 first2, ForwardIterator2 last2);
+
struct input_iterator_tag { };
struct output_iterator_tag { };
struct forward_iterator_tag : public input_iterator_tag { };
diff --git a/test/Analysis/diagnostics/explicit-suppression.cpp b/test/Analysis/diagnostics/explicit-suppression.cpp
index 67a47d02b6e9..d36def20f25f 100644
--- a/test/Analysis/diagnostics/explicit-suppression.cpp
+++ b/test/Analysis/diagnostics/explicit-suppression.cpp
@@ -18,6 +18,6 @@ class C {
void testCopyNull(C *I, C *E) {
std::copy(I, E, (C *)0);
#ifndef SUPPRESSED
- // expected-warning@../Inputs/system-header-simulator-cxx.h:166 {{Called C++ object pointer is null}}
+ // expected-warning@../Inputs/system-header-simulator-cxx.h:191 {{Called C++ object pointer is null}}
#endif
}
diff --git a/test/Analysis/inlining/stl.cpp b/test/Analysis/inlining/stl.cpp
index 95ac3f8172db..d89a10983041 100644
--- a/test/Analysis/inlining/stl.cpp
+++ b/test/Analysis/inlining/stl.cpp
@@ -6,8 +6,7 @@
void clang_analyzer_eval(bool);
void testVector(std::vector<int> &nums) {
- if (nums.begin()) return;
- if (nums.end()) return;
+ if (nums.begin() != nums.end()) return;
clang_analyzer_eval(nums.size() == 0);
#if INLINE
diff --git a/test/Analysis/iterator-past-end.cpp b/test/Analysis/iterator-past-end.cpp
new file mode 100644
index 000000000000..4d9ed0cf9816
--- /dev/null
+++ b/test/Analysis/iterator-past-end.cpp
@@ -0,0 +1,205 @@
+// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorPastEnd -analyzer-eagerly-assume -analyzer-config c++-container-inlining=false %s -verify
+// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorPastEnd -analyzer-eagerly-assume -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+void simple_good(const std::vector<int> &v) {
+ auto i = v.end();
+ if (i != v.end())
+ *i; // no-warning
+}
+
+void simple_good_negated(const std::vector<int> &v) {
+ auto i = v.end();
+ if (!(i == v.end()))
+ *i; // no-warning
+}
+
+void simple_bad(const std::vector<int> &v) {
+ auto i = v.end();
+ *i; // expected-warning{{Iterator accessed past its end}}
+}
+
+void copy(const std::vector<int> &v) {
+ auto i1 = v.end();
+ auto i2 = i1;
+ *i2; // expected-warning{{Iterator accessed past its end}}
+}
+
+void decrease(const std::vector<int> &v) {
+ auto i = v.end();
+ --i;
+ *i; // no-warning
+}
+
+void copy_and_decrease1(const std::vector<int> &v) {
+ auto i1 = v.end();
+ auto i2 = i1;
+ --i1;
+ *i1; // no-warning
+}
+
+void copy_and_decrease2(const std::vector<int> &v) {
+ auto i1 = v.end();
+ auto i2 = i1;
+ --i1;
+ *i2; // expected-warning{{Iterator accessed past its end}}
+}
+
+void copy_and_increase1(const std::vector<int> &v) {
+ auto i1 = v.begin();
+ auto i2 = i1;
+ ++i1;
+ if (i1 == v.end())
+ *i2; // no-warning
+}
+
+void copy_and_increase2(const std::vector<int> &v) {
+ auto i1 = v.begin();
+ auto i2 = i1;
+ ++i1;
+ if (i2 == v.end())
+ *i2; // expected-warning{{Iterator accessed past its end}}
+}
+
+void good_find(std::vector<int> &vec, int e) {
+ auto first = std::find(vec.begin(), vec.end(), e);
+ if (vec.end() != first)
+ *first; // no-warning
+}
+
+void bad_find(std::vector<int> &vec, int e) {
+ auto first = std::find(vec.begin(), vec.end(), e);
+ *first; // expected-warning{{Iterator accessed past its end}}
+}
+
+void good_find_end(std::vector<int> &vec, std::vector<int> &seq) {
+ auto last = std::find_end(vec.begin(), vec.end(), seq.begin(), seq.end());
+ if (vec.end() != last)
+ *last; // no-warning
+}
+
+void bad_find_end(std::vector<int> &vec, std::vector<int> &seq) {
+ auto last = std::find_end(vec.begin(), vec.end(), seq.begin(), seq.end());
+ *last; // expected-warning{{Iterator accessed past its end}}
+}
+
+void good_find_first_of(std::vector<int> &vec, std::vector<int> &seq) {
+ auto first =
+ std::find_first_of(vec.begin(), vec.end(), seq.begin(), seq.end());
+ if (vec.end() != first)
+ *first; // no-warning
+}
+
+void bad_find_first_of(std::vector<int> &vec, std::vector<int> &seq) {
+ auto first = std::find_end(vec.begin(), vec.end(), seq.begin(), seq.end());
+ *first; // expected-warning{{Iterator accessed past its end}}
+}
+
+bool odd(int i) { return i % 2; }
+
+void good_find_if(std::vector<int> &vec) {
+ auto first = std::find_if(vec.begin(), vec.end(), odd);
+ if (vec.end() != first)
+ *first; // no-warning
+}
+
+void bad_find_if(std::vector<int> &vec, int e) {
+ auto first = std::find_if(vec.begin(), vec.end(), odd);
+ *first; // expected-warning{{Iterator accessed past its end}}
+}
+
+void good_find_if_not(std::vector<int> &vec) {
+ auto first = std::find_if_not(vec.begin(), vec.end(), odd);
+ if (vec.end() != first)
+ *first; // no-warning
+}
+
+void bad_find_if_not(std::vector<int> &vec, int e) {
+ auto first = std::find_if_not(vec.begin(), vec.end(), odd);
+ *first; // expected-warning{{Iterator accessed past its end}}
+}
+
+void good_lower_bound(std::vector<int> &vec, int e) {
+ auto first = std::lower_bound(vec.begin(), vec.end(), e);
+ if (vec.end() != first)
+ *first; // no-warning
+}
+
+void bad_lower_bound(std::vector<int> &vec, int e) {
+ auto first = std::lower_bound(vec.begin(), vec.end(), e);
+ *first; // expected-warning{{Iterator accessed past its end}}
+}
+
+void good_upper_bound(std::vector<int> &vec, int e) {
+ auto last = std::lower_bound(vec.begin(), vec.end(), e);
+ if (vec.end() != last)
+ *last; // no-warning
+}
+
+void bad_upper_bound(std::vector<int> &vec, int e) {
+ auto last = std::lower_bound(vec.begin(), vec.end(), e);
+ *last; // expected-warning{{Iterator accessed past its end}}
+}
+
+void good_search(std::vector<int> &vec, std::vector<int> &seq) {
+ auto first = std::search(vec.begin(), vec.end(), seq.begin(), seq.end());
+ if (vec.end() != first)
+ *first; // no-warning
+}
+
+void bad_search(std::vector<int> &vec, std::vector<int> &seq) {
+ auto first = std::search(vec.begin(), vec.end(), seq.begin(), seq.end());
+ *first; // expected-warning{{Iterator accessed past its end}}
+}
+
+void good_search_n(std::vector<int> &vec, std::vector<int> &seq) {
+ auto nth = std::search_n(vec.begin(), vec.end(), seq.begin(), seq.end());
+ if (vec.end() != nth)
+ *nth; // no-warning
+}
+
+void bad_search_n(std::vector<int> &vec, std::vector<int> &seq) {
+ auto nth = std::search_n(vec.begin(), vec.end(), seq.begin(), seq.end());
+ *nth; // expected-warning{{Iterator accessed past its end}}
+}
+
+template <class InputIterator, class T>
+InputIterator nonStdFind(InputIterator first, InputIterator last,
+ const T &val) {
+ for (auto i = first; i != last; ++i) {
+ if (*i == val) {
+ return i;
+ }
+ }
+ return last;
+}
+
+void good_non_std_find(std::vector<int> &vec, int e) {
+ auto first = nonStdFind(vec.begin(), vec.end(), e);
+ if (vec.end() != first)
+ *first; // no-warning
+}
+
+void bad_non_std_find(std::vector<int> &vec, int e) {
+ auto first = nonStdFind(vec.begin(), vec.end(), e);
+ *first; // expected-warning{{Iterator accessed past its end}}
+}
+
+void tricky(std::vector<int> &vec, int e) {
+ const auto first = vec.begin();
+ const auto comp1 = (first != vec.end()), comp2 = (first == vec.end());
+ if (comp1)
+ *first;
+}
+
+void loop(std::vector<int> &vec, int e) {
+ auto start = vec.begin();
+ while (true) {
+ auto item = std::find(start, vec.end(), e);
+ if (item == vec.end())
+ break;
+ *item; // no-warning
+ start = ++item; // no-warning
+ }
+}
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp
index 3e04d5094ac1..74db2b80e70e 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp
@@ -28,14 +28,23 @@ namespace default_ctor {
struct C;
struct D;
+ struct convert_to_D1 {
+ operator D&&();
+ };
+ struct convert_to_D2 {
+ operator D&&();
+ };
+
struct A { // expected-note 4{{candidate}}
A(); // expected-note {{candidate}}
A(C &&); // expected-note {{candidate}}
C &operator=(C&&); // expected-note {{candidate}}
- A(D &&); // expected-note {{candidate}}
+ A(D &&);
D &operator=(D&&); // expected-note {{candidate}}
+
+ A(convert_to_D2); // expected-note {{candidate}}
};
struct B { // expected-note 4{{candidate}}
@@ -44,8 +53,10 @@ namespace default_ctor {
B(C &&); // expected-note {{candidate}}
C &operator=(C&&); // expected-note {{candidate}}
- B(D &&); // expected-note {{candidate}}
+ B(D &&);
D &operator=(D&&); // expected-note {{candidate}}
+
+ B(convert_to_D2); // expected-note {{candidate}}
};
struct C : A, B {
@@ -75,7 +86,20 @@ namespace default_ctor {
// versions are inherited.
D d; // expected-error {{ambiguous}}
void f(D d) {
- D d2(static_cast<D&&>(d)); // expected-error {{ambiguous}}
+ D d2(static_cast<D&&>(d)); // ok, ignores inherited constructors
+ D d3(convert_to_D1{}); // ok, ignores inherited constructors
+ D d4(convert_to_D2{}); // expected-error {{ambiguous}}
d = static_cast<D&&>(d); // expected-error {{ambiguous}}
}
+
+ struct Y;
+ struct X { // expected-note 2{{candidate}}
+ X();
+ X(volatile Y &); // expected-note {{constructor inherited from base class cannot be used to initialize from an argument of the derived class type}}
+ } x;
+ struct Y : X { using X::X; } volatile y; // expected-note 2{{candidate}}
+ struct Z : Y { using Y::Y; } volatile z; // expected-note 3{{candidate}} expected-note 5{{inherited here}}
+ Z z1(x); // ok
+ Z z2(y); // ok, Z is not reference-related to type of y
+ Z z3(z); // expected-error {{no match}}
}
diff --git a/test/CXX/drs/dr13xx.cpp b/test/CXX/drs/dr13xx.cpp
index 28bebcbb607e..28e667f77f84 100644
--- a/test/CXX/drs/dr13xx.cpp
+++ b/test/CXX/drs/dr13xx.cpp
@@ -174,3 +174,133 @@ namespace dr1359 { // dr1359: 3.5
constexpr Y y = Y(); // expected-error {{no matching}}
#endif
}
+
+namespace dr1388 { // dr1388: 4.0
+ template<typename A, typename ...T> void f(T..., A); // expected-note 1+{{candidate}} expected-error 0-1{{C++11}}
+ template<typename ...T> void g(T..., int); // expected-note 1+{{candidate}} expected-error 0-1{{C++11}}
+ template<typename ...T, typename A> void h(T..., A); // expected-note 1+{{candidate}} expected-error 0-1{{C++11}}
+
+ void test_f() {
+ f(0); // ok, trailing parameter pack deduced to empty
+ f(0, 0); // expected-error {{no matching}}
+ f<int>(0);
+ f<int>(0, 0); // expected-error {{no matching}}
+ f<int, int>(0, 0);
+ f<int, int, int>(0, 0); // expected-error {{no matching}}
+
+ g(0);
+ g(0, 0); // expected-error {{no matching}}
+ g<>(0);
+ g<int>(0); // expected-error {{no matching}}
+ g<int>(0, 0);
+
+ h(0);
+ h(0, 0); // expected-error {{no matching}}
+ h<int>(0, 0);
+ h<int, int>(0, 0); // expected-error {{no matching}}
+ }
+
+ // A non-trailing parameter pack is still a non-deduced context, even though
+ // we know exactly how many arguments correspond to it.
+ template<typename T, typename U> struct pair {};
+ template<typename ...T> struct tuple { typedef char type; }; // expected-error 0-2{{C++11}}
+ template<typename ...T, typename ...U> void f_pair_1(pair<T, U>..., int); // expected-error 0-2{{C++11}} expected-note {{different lengths (2 vs. 0)}}
+ template<typename ...T, typename U> void f_pair_2(pair<T, char>..., U); // expected-error 0-2{{C++11}}
+ template<typename ...T, typename ...U> void f_pair_3(pair<T, U>..., tuple<U...>); // expected-error 0-2{{C++11}} expected-note {{different lengths (2 vs. 1)}}
+ template<typename ...T> void f_pair_4(pair<T, char>..., T...); // expected-error 0-2{{C++11}} expected-note {{<int, long> vs. <int, long, const char *>}}
+ void g(pair<int, char> a, pair<long, char> b, tuple<char, char> c) {
+ f_pair_1<int, long>(a, b, 0); // expected-error {{no match}}
+ f_pair_2<int, long>(a, b, 0);
+ f_pair_3<int, long>(a, b, c);
+ f_pair_3<int, long>(a, b, tuple<char>()); // expected-error {{no match}}
+ f_pair_4<int, long>(a, b, 0, 0L);
+ f_pair_4<int, long>(a, b, 0, 0L, "foo"); // expected-error {{no match}}
+ }
+}
+
+namespace dr1391 { // dr1391: partial
+ struct A {}; struct B : A {};
+ template<typename T> struct C { C(int); typename T::error error; }; // expected-error 2{{'::'}}
+ template<typename T> struct D {};
+
+ // No deduction is performed for parameters with no deducible template-parameters, therefore types do not need to match.
+ template<typename T> void a(T, int T::*);
+ void test_a(int A::*p) { a(A(), p); } // ok, type of second parameter does not need to match
+
+ namespace dr_example_1 {
+ template<typename T, typename U> void f(C<T>);
+ template<typename T> void f(D<T>);
+
+ void g(D<int> d) {
+ f(d); // ok, first 'f' eliminated by deduction failure
+ f<int>(d); // ok, first 'f' eliminated because 'U' cannot be deduced
+ }
+ }
+
+ namespace dr_example_2 {
+ template<typename T> typename C<T>::error f(int, T);
+ template<typename T> T f(T, T);
+
+ void g(A a) {
+ f(a, a); // ok, no conversion from A to int for first parameter of first candidate
+ }
+ }
+
+ namespace std_example {
+ template<typename T> struct Z {
+ typedef typename T::x xx;
+ };
+ template<typename T> typename Z<T>::xx f(void *, T);
+ template<typename T> void f(int, T);
+ struct A {} a;
+ void g() { f(1, a); }
+ }
+
+ template<typename T> void b(C<int> ci, T *p);
+ void b(...);
+ void test_b() {
+ b(0, 0); // ok, deduction fails prior to forming a conversion sequence and instantiating C<int>
+ // FIXME: The "while substituting" note should point at the overload candidate.
+ b<int>(0, 0); // expected-note {{instantiation of}} expected-note {{while substituting}}
+ }
+
+ template<typename T> struct Id { typedef T type; };
+ template<typename T> void c(T, typename Id<C<T> >::type);
+ void test_c() {
+ // Implicit conversion sequences for dependent types are checked later.
+ c(0.0, 0); // expected-note {{instantiation of}}
+ }
+
+ namespace partial_ordering {
+ // FIXME: Second template should be considered more specialized because non-dependent parameter is ignored.
+ template<typename T> int a(T, short) = delete; // expected-error 0-1{{extension}} expected-note {{candidate}}
+ template<typename T> int a(T*, char); // expected-note {{candidate}}
+ int test_a = a((int*)0, 0); // FIXME: expected-error {{ambiguous}}
+
+ // FIXME: Second template should be considered more specialized:
+ // deducing #1 from #2 ignores the second P/A pair, so deduction succeeds,
+ // deducing #2 from #1 fails to deduce T, so deduction fails.
+ template<typename T> int b(T, int) = delete; // expected-error 0-1{{extension}} expected-note {{candidate}}
+ template<typename T, typename U> int b(T*, U); // expected-note {{candidate}}
+ int test_b = b((int*)0, 0); // FIXME: expected-error {{ambiguous}}
+
+ // Unintended consequences: because partial ordering does not consider
+ // explicit template arguments, and deduction from a non-dependent type
+ // vacuously succeeds, a non-dependent template is less specialized than
+ // anything else!
+ // According to DR1391, this is ambiguous!
+ template<typename T> int c(int);
+ template<typename T> int c(T);
+ int test_c1 = c(0); // ok
+ int test_c2 = c<int>(0); // FIXME: apparently ambiguous
+ }
+}
+
+namespace dr1399 { // dr1399: dup 1388
+ template<typename ...T> void f(T..., int, T...) {} // expected-note {{candidate}} expected-error 0-1{{C++11}}
+ void g() {
+ f(0);
+ f<int>(0, 0, 0);
+ f(0, 0, 0); // expected-error {{no match}}
+ }
+}
diff --git a/test/CXX/drs/dr19xx.cpp b/test/CXX/drs/dr19xx.cpp
index 5b626dd80892..15ed30583fd0 100644
--- a/test/CXX/drs/dr19xx.cpp
+++ b/test/CXX/drs/dr19xx.cpp
@@ -140,7 +140,7 @@ namespace dr1959 { // dr1959: 3.9
a() = default;
a(const a &) = delete; // expected-note 2{{deleted}}
a(const b &) = delete; // not inherited
- a(c &&) = delete; // expected-note {{deleted}}
+ a(c &&) = delete;
template<typename T> a(T) = delete;
};
@@ -152,13 +152,14 @@ namespace dr1959 { // dr1959: 3.9
b y = x; // expected-error {{deleted}}
b z = z; // expected-error {{deleted}}
- // FIXME: It's not really clear that this matches the intent, but it's
- // consistent with the behavior for assignment operators.
struct c : a {
using a::a;
c(const c &);
};
- c q(static_cast<c&&>(q)); // expected-error {{call to deleted}}
+ // FIXME: As a resolution to an open DR against P0136R0, we disallow
+ // use of inherited constructors to construct from a single argument
+ // where the derived class is reference-related to its type.
+ c q(static_cast<c&&>(q));
#endif
}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
index e40761770d55..31213c9ebc33 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
@@ -139,11 +139,11 @@ namespace NonLocalLambdaInstantation {
}
template<typename T>
- struct X2 { // expected-note{{in instantiation of default member initializer 'NonLocalLambdaInstantation::X2<int *>::x' requested here}}
+ struct X2 {
int x = []{ return T(); }(); // expected-error{{cannot initialize a member subobject of type 'int' with an rvalue of type 'int *'}}
};
X2<int> x2i;
X2<float> x2f;
- X2<int*> x2ip; // expected-note{{implicit default constructor for 'NonLocalLambdaInstantation::X2<int *>' first required here}}
+ X2<int*> x2ip; // expected-note{{in instantiation of default member initializer 'NonLocalLambdaInstantation::X2<int *>::x'}}
}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
index cd1d9f15c725..081bba2b8dff 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
@@ -76,14 +76,17 @@ void test_pair_deduction(int *ip, float *fp, double *dp) {
first_arg_pair(make_pair(ip, 17), 16); // expected-error{{no matching function for call to 'first_arg_pair'}}
}
-// For a function parameter pack that does not occur at the end of the
-// parameter-declaration-list, the type of the parameter pack is a
-// non-deduced context.
+// A function parameter pack not at the end of the parameter list is never
+// deduced. We interpret this as meaning the types within it are never
+// deduced, and thus must match explicitly-specified values.
template<typename ...Types> struct tuple { };
template<typename ...Types>
-void pack_not_at_end(tuple<Types...>, Types... values, int);
+void pack_not_at_end(tuple<Types...>, Types... values, int); // expected-note {{<int *, double *> vs. <>}}
void test_pack_not_at_end(tuple<int*, double*> t2) {
- pack_not_at_end(t2, 0, 0, 0);
+ pack_not_at_end(t2, 0, 0, 0); // expected-error {{no match}}
+ // FIXME: Should the "original argument type must match deduced parameter
+ // type" rule apply here?
+ pack_not_at_end<int*, double*>(t2, 0, 0, 0); // ok
}
diff --git a/test/CXX/temp/temp.param/p5.cpp b/test/CXX/temp/temp.param/p5.cpp
index ab430fb8741f..aa0d7e92b9ec 100644
--- a/test/CXX/temp/temp.param/p5.cpp
+++ b/test/CXX/temp/temp.param/p5.cpp
@@ -1,13 +1,13 @@
-// RUN: %clang_cc1 -verify %s -std=c++11
+// RUN: %clang_cc1 -verify %s -std=c++14
-template<const int I> struct S { // expected-note {{instantiation}}
+template<const int I> struct S {
decltype(I) n;
int &&r = I; // expected-warning 2{{binding reference member 'r' to a temporary value}} expected-note 2{{declared here}}
};
-S<5> s;
+S<5> s; // expected-note {{instantiation}}
-template<typename T, T v> struct U { // expected-note {{instantiation}}
+template<typename T, T v> struct U {
decltype(v) n;
int &&r = v; // expected-warning {{binding reference member 'r' to a temporary value}} expected-note {{declared here}}
};
-U<const int, 6> u;
+U<const int, 6> u; // expected-note {{instantiation}}
diff --git a/test/CodeGen/lifetime2.c b/test/CodeGen/lifetime2.c
index 0d22282fdd43..4374b3c279c7 100644
--- a/test/CodeGen/lifetime2.c
+++ b/test/CodeGen/lifetime2.c
@@ -1,4 +1,6 @@
// RUN: %clang -S -emit-llvm -o - -O2 %s | FileCheck %s -check-prefixes=CHECK,O2
+// RUN: %clang -S -emit-llvm -o - -O2 -Xclang -disable-lifetime-markers %s \
+// RUN: | FileCheck %s -check-prefixes=CHECK,O0
// RUN: %clang -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefixes=CHECK,O0
extern int bar(char *A, int n);
diff --git a/test/CodeGen/thinlto_backend.ll b/test/CodeGen/thinlto_backend.ll
index 89f4fc407fbc..ac0b3b76ef7d 100644
--- a/test/CodeGen/thinlto_backend.ll
+++ b/test/CodeGen/thinlto_backend.ll
@@ -12,6 +12,14 @@
; RUN: %clang -O2 -o %t4.o -x ir %t1.o -c -fthinlto-index=bad.thinlto.bc 2>&1 | FileCheck %s -check-prefix=CHECK-ERROR1
; CHECK-ERROR1: Error loading index file 'bad.thinlto.bc'
+; Ensure we ignore empty index file under -ignore-empty-index-file, and run
+; non-ThinLTO compilation which would not import f2
+; RUN: touch %t4.thinlto.bc
+; RUN: %clang -target x86_64-unknown-linux-gnu -O2 -o %t4.o -x ir %t1.o -c -fthinlto-index=%t4.thinlto.bc -mllvm -ignore-empty-index-file
+; RUN: llvm-nm %t4.o | FileCheck --check-prefix=CHECK-OBJ-IGNORE-EMPTY %s
+; CHECK-OBJ-IGNORE-EMPTY: T f1
+; CHECK-OBJ-IGNORE-EMPTY: U f2
+
; Ensure f2 was imported
; 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/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
index d0b896d182da..7eba017e37f2 100644
--- a/test/CodeGenCXX/arm.cpp
+++ b/test/CodeGenCXX/arm.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -triple=thumbv7-apple-ios6.0 -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -o - -fexceptions | FileCheck %s
+// RUN: %clang_cc1 %s -triple=thumbv7-apple-ios6.0 -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -std=gnu++98 -o - -fexceptions | FileCheck -check-prefix=CHECK -check-prefix=CHECK98 %s
+// RUN: %clang_cc1 %s -triple=thumbv7-apple-ios6.0 -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -std=gnu++11 -o - -fexceptions | FileCheck -check-prefix=CHECK -check-prefix=CHECK11 %s
// CHECK: @_ZZN5test74testEvE1x = internal global i32 0, align 4
// CHECK: @_ZGVZN5test74testEvE1x = internal global i32 0
@@ -156,7 +157,8 @@ namespace test3 {
// CHECK: getelementptr {{.*}}, i32 4
// CHECK: bitcast {{.*}} to i32*
// CHECK: load
- // CHECK: invoke {{.*}} @_ZN5test31AD1Ev
+ // CHECK98: invoke {{.*}} @_ZN5test31AD1Ev
+ // CHECK11: call {{.*}} @_ZN5test31AD1Ev
// CHECK: call void @_ZdaPv
delete [] x;
}
@@ -168,7 +170,8 @@ namespace test3 {
// CHECK: getelementptr {{.*}}, i32 4
// CHECK: bitcast {{.*}} to i32*
// CHECK: load
- // CHECK: invoke {{.*}} @_ZN5test31AD1Ev
+ // CHECK98: invoke {{.*}} @_ZN5test31AD1Ev
+ // CHECK11: call {{.*}} @_ZN5test31AD1Ev
// CHECK: call void @_ZdaPv
delete [] x;
}
diff --git a/test/CodeGenCXX/debug-info-class.cpp b/test/CodeGenCXX/debug-info-class.cpp
index d572eef68abf..e06ef8dfda5b 100644
--- a/test/CodeGenCXX/debug-info-class.cpp
+++ b/test/CodeGenCXX/debug-info-class.cpp
@@ -83,12 +83,17 @@ int main(int argc, char **argv) {
return 0;
}
-// RUN: %clang_cc1 -triple x86_64-unknown_unknown -emit-llvm -debug-info-kind=limited -fexceptions %s -o - | FileCheck %s
-// RUN: %clang_cc1 -triple i686-cygwin -emit-llvm -debug-info-kind=limited -fexceptions %s -o - | FileCheck %s
-// RUN: %clang_cc1 -triple armv7l-unknown-linux-gnueabihf -emit-llvm -debug-info-kind=limited -fexceptions %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown_unknown -emit-llvm -debug-info-kind=limited -fexceptions -std=c++98 %s -o - | FileCheck -check-prefix=CHECK98 %s
+// RUN: %clang_cc1 -triple i686-cygwin -emit-llvm -debug-info-kind=limited -fexceptions -std=c++98 %s -o - | FileCheck -check-prefix=CHECK98 %s
+// RUN: %clang_cc1 -triple armv7l-unknown-linux-gnueabihf -emit-llvm -debug-info-kind=limited -fexceptions -std=c++98 %s -o - | FileCheck -check-prefix=CHECK98 %s
+// RUN: %clang_cc1 -triple x86_64-unknown_unknown -emit-llvm -debug-info-kind=limited -fexceptions -std=c++11 %s -o - | FileCheck -check-prefix=CHECK11 %s
+// RUN: %clang_cc1 -triple i686-cygwin -emit-llvm -debug-info-kind=limited -fexceptions -std=c++11 %s -o - | FileCheck -check-prefix=CHECK11 %s
+// RUN: %clang_cc1 -triple armv7l-unknown-linux-gnueabihf -emit-llvm -debug-info-kind=limited -fexceptions -std=c++11 %s -o - | FileCheck -check-prefix=CHECK11 %s
+
+// CHECK98: invoke {{.+}} @_ZN1BD1Ev(%class.B* %b)
+// CHECK98-NEXT: unwind label %{{.+}}, !dbg ![[EXCEPTLOC:.*]]
+// CHECK11: call {{.+}} @_ZN1BD1Ev(%class.B* %b){{.*}}, !dbg ![[EXCEPTLOC:.*]]
-// CHECK: invoke {{.+}} @_ZN1BD1Ev(%class.B* %b)
-// CHECK-NEXT: unwind label %{{.+}}, !dbg ![[EXCEPTLOC:.*]]
// CHECK: store i32 0, i32* %{{.+}}, !dbg ![[RETLOC:.*]]
// CHECK: [[F:![0-9]*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "F"
diff --git a/test/CodeGenCXX/dllexport-ctor-closure.cpp b/test/CodeGenCXX/dllexport-ctor-closure.cpp
new file mode 100644
index 000000000000..4fae7e10e8b6
--- /dev/null
+++ b/test/CodeGenCXX/dllexport-ctor-closure.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++14 \
+// RUN: -fno-threadsafe-statics -fms-extensions -O1 -mconstructor-aliases \
+// RUN: -disable-llvm-passes -o - %s -w -fms-compatibility-version=19.00 | \
+// RUN: FileCheck %s
+
+struct CtorWithClosure {
+ __declspec(dllexport) CtorWithClosure(...) {}
+// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_FCtorWithClosure@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
+// CHECK: %[[this_addr:.*]] = alloca %struct.CtorWithClosure*, align 4
+// CHECK: store %struct.CtorWithClosure* %this, %struct.CtorWithClosure** %[[this_addr]], align 4
+// CHECK: %[[this:.*]] = load %struct.CtorWithClosure*, %struct.CtorWithClosure** %[[this_addr]]
+// CHECK: call %struct.CtorWithClosure* (%struct.CtorWithClosure*, ...) @"\01??0CtorWithClosure@@QAA@ZZ"(%struct.CtorWithClosure* %[[this]])
+// CHECK: ret void
+};
+
+struct CtorWithClosureOutOfLine {
+ __declspec(dllexport) CtorWithClosureOutOfLine(...);
+};
+CtorWithClosureOutOfLine::CtorWithClosureOutOfLine(...) {}
+// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_FCtorWithClosureOutOfLine@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
+
+#define DELETE_IMPLICIT_MEMBERS(ClassName) \
+ ClassName(ClassName &&) = delete; \
+ ClassName(ClassName &) = delete; \
+ ~ClassName() = delete; \
+ ClassName &operator=(ClassName &) = delete
+
+struct __declspec(dllexport) ClassWithClosure {
+ DELETE_IMPLICIT_MEMBERS(ClassWithClosure);
+ ClassWithClosure(...) {}
+// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_FClassWithClosure@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
+// CHECK: %[[this_addr:.*]] = alloca %struct.ClassWithClosure*, align 4
+// CHECK: store %struct.ClassWithClosure* %this, %struct.ClassWithClosure** %[[this_addr]], align 4
+// CHECK: %[[this:.*]] = load %struct.ClassWithClosure*, %struct.ClassWithClosure** %[[this_addr]]
+// CHECK: call %struct.ClassWithClosure* (%struct.ClassWithClosure*, ...) @"\01??0ClassWithClosure@@QAA@ZZ"(%struct.ClassWithClosure* %[[this]])
+// CHECK: ret void
+};
+
+template <typename T> struct TemplateWithClosure {
+ TemplateWithClosure(int x = sizeof(T)) {}
+};
+extern template struct TemplateWithClosure<char>;
+template struct __declspec(dllexport) TemplateWithClosure<char>;
+extern template struct TemplateWithClosure<int>;
+template struct __declspec(dllexport) TemplateWithClosure<int>;
+
+// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_F?$TemplateWithClosure@D@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
+// CHECK: call {{.*}} @"\01??0?$TemplateWithClosure@D@@QAE@H@Z"({{.*}}, i32 1)
+
+// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_F?$TemplateWithClosure@H@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
+// CHECK: call {{.*}} @"\01??0?$TemplateWithClosure@H@@QAE@H@Z"({{.*}}, i32 4)
+
+struct __declspec(dllexport) NestedOuter {
+ DELETE_IMPLICIT_MEMBERS(NestedOuter);
+ NestedOuter(void *p = 0) {}
+ struct __declspec(dllexport) NestedInner {
+ DELETE_IMPLICIT_MEMBERS(NestedInner);
+ NestedInner(void *p = 0) {}
+ };
+};
+
+// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_FNestedOuter@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
+// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_FNestedInner@NestedOuter@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
+
+struct HasDtor {
+ ~HasDtor();
+ int o;
+};
+struct HasImplicitDtor1 { HasDtor o; };
+struct HasImplicitDtor2 { HasDtor o; };
+struct __declspec(dllexport) CtorClosureInline {
+ CtorClosureInline(const HasImplicitDtor1 &v = {}) {}
+};
+struct __declspec(dllexport) CtorClosureOutOfLine {
+ CtorClosureOutOfLine(const HasImplicitDtor2 &v = {});
+};
+CtorClosureOutOfLine::CtorClosureOutOfLine(const HasImplicitDtor2 &v) {}
+
+// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_FCtorClosureInline@@QAEXXZ"
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??1HasImplicitDtor1@@QAE@XZ"
+// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_FCtorClosureOutOfLine@@QAEXXZ"
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??1HasImplicitDtor2@@QAE@XZ"
diff --git a/test/CodeGenCXX/dllexport.cpp b/test/CodeGenCXX/dllexport.cpp
index 116176e2cb92..fe40bc0aac12 100644
--- a/test/CodeGenCXX/dllexport.cpp
+++ b/test/CodeGenCXX/dllexport.cpp
@@ -488,57 +488,6 @@ struct S {
};
};
-struct CtorWithClosure {
- __declspec(dllexport) CtorWithClosure(...) {}
-// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FCtorWithClosure@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
-// M32-DAG: %[[this_addr:.*]] = alloca %struct.CtorWithClosure*, align 4
-// M32-DAG: store %struct.CtorWithClosure* %this, %struct.CtorWithClosure** %[[this_addr]], align 4
-// M32-DAG: %[[this:.*]] = load %struct.CtorWithClosure*, %struct.CtorWithClosure** %[[this_addr]]
-// M32-DAG: call %struct.CtorWithClosure* (%struct.CtorWithClosure*, ...) @"\01??0CtorWithClosure@@QAA@ZZ"(%struct.CtorWithClosure* %[[this]])
-// M32-DAG: ret void
-};
-
-#define DELETE_IMPLICIT_MEMBERS(ClassName) \
- ClassName(ClassName &&) = delete; \
- ClassName(ClassName &) = delete; \
- ~ClassName() = delete; \
- ClassName &operator=(ClassName &) = delete
-
-struct __declspec(dllexport) ClassWithClosure {
- DELETE_IMPLICIT_MEMBERS(ClassWithClosure);
- ClassWithClosure(...) {}
-// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FClassWithClosure@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
-// M32-DAG: %[[this_addr:.*]] = alloca %struct.ClassWithClosure*, align 4
-// M32-DAG: store %struct.ClassWithClosure* %this, %struct.ClassWithClosure** %[[this_addr]], align 4
-// M32-DAG: %[[this:.*]] = load %struct.ClassWithClosure*, %struct.ClassWithClosure** %[[this_addr]]
-// M32-DAG: call %struct.ClassWithClosure* (%struct.ClassWithClosure*, ...) @"\01??0ClassWithClosure@@QAA@ZZ"(%struct.ClassWithClosure* %[[this]])
-// M32-DAG: ret void
-};
-
-template <typename T> struct TemplateWithClosure {
- TemplateWithClosure(int x = sizeof(T)) {}
-};
-extern template struct TemplateWithClosure<char>;
-template struct __declspec(dllexport) TemplateWithClosure<char>;
-extern template struct TemplateWithClosure<int>;
-template struct __declspec(dllexport) TemplateWithClosure<int>;
-// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_F?$TemplateWithClosure@D@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
-// M32-DAG: call {{.*}} @"\01??0?$TemplateWithClosure@D@@QAE@H@Z"({{.*}}, i32 1)
-// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_F?$TemplateWithClosure@H@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
-// M32-DAG: call {{.*}} @"\01??0?$TemplateWithClosure@H@@QAE@H@Z"({{.*}}, i32 4)
-
-struct __declspec(dllexport) NestedOuter {
- DELETE_IMPLICIT_MEMBERS(NestedOuter);
- NestedOuter(void *p = 0) {}
- struct __declspec(dllexport) NestedInner {
- DELETE_IMPLICIT_MEMBERS(NestedInner);
- NestedInner(void *p = 0) {}
- };
-};
-
-// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FNestedOuter@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
-// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FNestedInner@NestedOuter@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
-
template <typename T>
struct SomeTemplate {
SomeTemplate(T o = T()) : o(o) {}
diff --git a/test/CodeGenCXX/eh-aggregate-copy-destroy.cpp b/test/CodeGenCXX/eh-aggregate-copy-destroy.cpp
index 29fb5567fb1d..9f0f36c87561 100644
--- a/test/CodeGenCXX/eh-aggregate-copy-destroy.cpp
+++ b/test/CodeGenCXX/eh-aggregate-copy-destroy.cpp
@@ -1,7 +1,8 @@
// Check that in case of copying an array of memcpy-able objects, their
// destructors will be called if an exception is thrown.
//
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fexceptions -fcxx-exceptions -O0 -fno-elide-constructors -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fexceptions -fcxx-exceptions -O0 -fno-elide-constructors -std=c++98 -emit-llvm %s -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK98 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fexceptions -fcxx-exceptions -O0 -fno-elide-constructors -std=c++11 -emit-llvm %s -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK11 %s
struct ImplicitCopy {
int x;
@@ -25,7 +26,8 @@ int main () {
// CHECK_LABEL: main
// CHECK-NOT: call void @_ZN9ThrowCopyC1ERKS_
// CHECK: invoke void @_ZN9ThrowCopyC1ERKS_
- // CHECK: invoke void @_ZN12ImplicitCopyD1Ev
+ // CHECK98: invoke void @_ZN12ImplicitCopyD1Ev
+ // CHECK11: call void @_ZN12ImplicitCopyD1Ev
Container c2(c1);
}
catch (...) {
diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp
index 86616d1e2c62..e31d6fc2797b 100644
--- a/test/CodeGenCXX/exceptions.cpp
+++ b/test/CodeGenCXX/exceptions.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -std=c++98 -o - -fcxx-exceptions -fexceptions | FileCheck -check-prefix=CHECK -check-prefix=CHECK98 %s
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -std=c++11 -o - -fcxx-exceptions -fexceptions | FileCheck -check-prefix=CHECK -check-prefix=CHECK11 %s
typedef __typeof(sizeof(0)) size_t;
@@ -64,7 +65,10 @@ namespace test1 {
// CHECK-NEXT: [[T2:%.*]] = load i32, i32* [[T1]], align 4
// CHECK-NEXT: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[T2]])
// CHECK: store i1 false, i1* [[ACTIVE]]
- // CHECK-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]])
+
+ // CHECK98-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]])
+ // CHECK11-NEXT: call void @_ZN5test11BD1Ev([[B]]* [[T0]])
+
// CHECK: ret [[A]]* [[CAST]]
// CHECK: [[ISACTIVE:%.*]] = load i1, i1* [[ACTIVE]]
// CHECK-NEXT: br i1 [[ISACTIVE]]
@@ -74,10 +78,10 @@ namespace test1 {
// rdar://11904428
// Terminate landing pads should call __cxa_begin_catch first.
- // CHECK: define linkonce_odr hidden void @__clang_call_terminate(i8*) [[NI_NR_NUW:#[0-9]+]] comdat
- // CHECK-NEXT: [[T0:%.*]] = call i8* @__cxa_begin_catch(i8* %0) [[NUW:#[0-9]+]]
- // CHECK-NEXT: call void @_ZSt9terminatev() [[NR_NUW:#[0-9]+]]
- // CHECK-NEXT: unreachable
+ // CHECK98: define linkonce_odr hidden void @__clang_call_terminate(i8*) [[NI_NR_NUW:#[0-9]+]] comdat
+ // CHECK98-NEXT: [[T0:%.*]] = call i8* @__cxa_begin_catch(i8* %0) [[NUW:#[0-9]+]]
+ // CHECK98-NEXT: call void @_ZSt9terminatev() [[NR_NUW:#[0-9]+]]
+ // CHECK98-NEXT: unreachable
A *d() {
// CHECK: define [[A:%.*]]* @_ZN5test11dEv()
@@ -89,7 +93,10 @@ namespace test1 {
// CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]])
// CHECK: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[T1]])
// CHECK: store i1 false, i1* [[ACTIVE]]
- // CHECK-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]])
+
+ // CHECK98-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]])
+ // CHECK11-NEXT: call void @_ZN5test11BD1Ev([[B]]* [[T0]])
+
// CHECK: ret [[A]]* [[CAST]]
// CHECK: [[ISACTIVE:%.*]] = load i1, i1* [[ACTIVE]]
// CHECK-NEXT: br i1 [[ISACTIVE]]
@@ -109,8 +116,13 @@ namespace test1 {
// CHECK: [[T3:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T2]])
// CHECK: invoke void @_ZN5test11AC1Eii([[A]]* [[CAST]], i32 [[T1]], i32 [[T3]])
// CHECK: store i1 false, i1* [[ACTIVE]]
- // CHECK-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T2]])
- // CHECK: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]])
+
+ // CHECK98-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T2]])
+ // CHECK11-NEXT: call void @_ZN5test11BD1Ev([[B]]* [[T2]])
+
+ // CHECK98: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]])
+ // CHECK11: call void @_ZN5test11BD1Ev([[B]]* [[T0]])
+
// CHECK: ret [[A]]* [[CAST]]
// CHECK: [[ISACTIVE:%.*]] = load i1, i1* [[ACTIVE]]
// CHECK-NEXT: br i1 [[ISACTIVE]]
@@ -141,8 +153,13 @@ namespace test1 {
// CHECK-NEXT: store [[A]]* [[CAST]], [[A]]** [[X]], align 8
// CHECK: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret [[T2:%.*]])
// CHECK: [[RET:%.*]] = load [[A]]*, [[A]]** [[X]], align 8
- // CHECK: invoke void @_ZN5test11BD1Ev([[B]]* [[T2]])
- // CHECK: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]])
+
+ // CHECK98: invoke void @_ZN5test11BD1Ev([[B]]* [[T2]])
+ // CHECK11: call void @_ZN5test11BD1Ev([[B]]* [[T2]])
+
+ // CHECK98: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]])
+ // CHECK11: call void @_ZN5test11BD1Ev([[B]]* [[T0]])
+
// CHECK: ret [[A]]* [[RET]]
// CHECK: [[ISACTIVE:%.*]] = load i1, i1* [[ACTIVE]]
// CHECK-NEXT: br i1 [[ISACTIVE]]
@@ -166,8 +183,11 @@ namespace test2 {
// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]*
// CHECK-NEXT: invoke void @_ZN5test21AC1Ei([[A]]* [[CAST]], i32 5)
// CHECK: ret [[A]]* [[CAST]]
- // CHECK: invoke void @_ZN5test21AdlEPvm(i8* [[NEW]], i64 8)
- // CHECK: call void @__clang_call_terminate(i8* {{%.*}}) [[NR_NUW]]
+
+ // CHECK98: invoke void @_ZN5test21AdlEPvm(i8* [[NEW]], i64 8)
+ // CHECK11: call void @_ZN5test21AdlEPvm(i8* [[NEW]], i64 8)
+
+ // CHECK98: call void @__clang_call_terminate(i8* {{%.*}}) [[NR_NUW]]
return new A(5);
}
}
@@ -192,8 +212,11 @@ namespace test3 {
// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]*
// CHECK-NEXT: invoke void @_ZN5test31AC1Ei([[A]]* [[CAST]], i32 5)
// CHECK: ret [[A]]* [[CAST]]
- // CHECK: invoke void @_ZN5test31AdlEPvS1_d(i8* [[NEW]], i8* [[FOO]], double [[BAR]])
- // CHECK: call void @__clang_call_terminate(i8* {{%.*}}) [[NR_NUW]]
+
+ // CHECK98: invoke void @_ZN5test31AdlEPvS1_d(i8* [[NEW]], i8* [[FOO]], double [[BAR]])
+ // CHECK11: call void @_ZN5test31AdlEPvS1_d(i8* [[NEW]], i8* [[FOO]], double [[BAR]])
+
+ // CHECK98: call void @__clang_call_terminate(i8* {{%.*}}) [[NR_NUW]]
return new(foo(),bar()) A(5);
}
@@ -235,7 +258,9 @@ namespace test3 {
// CHECK-NEXT: br i1 [[ISACTIVE]]
// CHECK: [[V0:%.*]] = load i8*, i8** [[SAVED0]]
// CHECK-NEXT: [[V1:%.*]] = load i8*, i8** [[SAVED1]]
- // CHECK-NEXT: invoke void @_ZN5test31AdlEPvS1_d(i8* [[V0]], i8* [[V1]], double [[CONST]])
+
+ // CHECK98-NEXT: invoke void @_ZN5test31AdlEPvS1_d(i8* [[V0]], i8* [[V1]], double [[CONST]])
+ // CHECK11-NEXT: call void @_ZN5test31AdlEPvS1_d(i8* [[V0]], i8* [[V1]], double [[CONST]])
}
}
@@ -283,9 +308,13 @@ namespace test5 {
// CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[ADJ]] to [[A_T]]*
// CHECK-NEXT: invoke void @_ZN5test51TC1Ev([[T_T]]* [[T]])
// CHECK: invoke void @_ZN5test51AC1ERKS0_RKNS_1TE([[A_T]]* [[A]], [[A_T]]* dereferenceable({{[0-9]+}}) [[SRC]], [[T_T]]* dereferenceable({{[0-9]+}}) [[T]])
- // CHECK: invoke void @_ZN5test51TD1Ev([[T_T]]* [[T]])
- // CHECK: call i8* @__cxa_begin_catch(i8* [[EXN]]) [[NUW]]
- // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A_T]]* [[A]])
+
+ // CHECK98: invoke void @_ZN5test51TD1Ev([[T_T]]* [[T]])
+ // CHECK11: call void @_ZN5test51TD1Ev([[T_T]]* [[T]])
+
+ // CHECK98: call i8* @__cxa_begin_catch(i8* [[EXN]]) [[NUW]]
+ // CHECK98-NEXT: invoke void @_ZN5test51AD1Ev([[A_T]]* [[A]])
+
// CHECK: call void @__cxa_end_catch()
void test() {
try {
@@ -380,12 +409,16 @@ namespace test7 {
// Destroy the inner A object.
// CHECK-NEXT: load i1, i1* [[INNER_A]]
// CHECK-NEXT: br i1
- // CHECK: invoke void @_ZN5test71AD1Ev(
+
+ // CHECK98: invoke void @_ZN5test71AD1Ev(
+ // CHECK11: call void @_ZN5test71AD1Ev(
// Destroy the outer A object.
// CHECK: load i1, i1* [[OUTER_A]]
// CHECK-NEXT: br i1
- // CHECK: invoke void @_ZN5test71AD1Ev(
+
+ // CHECK98: invoke void @_ZN5test71AD1Ev(
+ // CHECK11: call void @_ZN5test71AD1Ev(
return new B(A(), new B(A(), 0));
}
@@ -456,8 +489,12 @@ namespace test10 {
// CHECK-NEXT: load i8, i8* @_ZN6test108suppressE, align 1
// CHECK-NEXT: trunc
// CHECK-NEXT: br i1
- // CHECK: call void @__cxa_end_catch()
- // CHECK-NEXT: br label
+
+ // CHECK98: call void @__cxa_end_catch()
+ // CHECK98-NEXT: br label
+ // CHECK11: invoke void @__cxa_end_catch()
+ // CHECK11-NEXT: to label
+
// CHECK: invoke void @__cxa_rethrow()
// CHECK: unreachable
}
@@ -504,7 +541,10 @@ namespace test11 {
// CHECK-NEXT: br i1 [[EMPTY]]
// CHECK: [[AFTER:%.*]] = phi [[A]]* [ [[CUR]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
// CHECK-NEXT: [[ELT]] = getelementptr inbounds [[A]], [[A]]* [[AFTER]], i64 -1
- // CHECK-NEXT: invoke void @_ZN6test111AD1Ev([[A]]* [[ELT]])
+
+ // CHECK98-NEXT: invoke void @_ZN6test111AD1Ev([[A]]* [[ELT]])
+ // CHECK11-NEXT: call void @_ZN6test111AD1Ev([[A]]* [[ELT]])
+
// CHECK: [[DONE:%.*]] = icmp eq [[A]]* [[ELT]], [[ARRAYBEGIN]]
// CHECK-NEXT: br i1 [[DONE]],
// - Next, chain to cleanup for single.
@@ -517,13 +557,19 @@ namespace test11 {
// CHECK-NEXT: br label
// CHECK: [[AFTER:%.*]] = phi [[A]]* [ [[ARRAYEND]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
// CHECK-NEXT: [[ELT]] = getelementptr inbounds [[A]], [[A]]* [[AFTER]], i64 -1
- // CHECK-NEXT: invoke void @_ZN6test111AD1Ev([[A]]* [[ELT]])
+
+ // CHECK98-NEXT: invoke void @_ZN6test111AD1Ev([[A]]* [[ELT]])
+ // CHECK11-NEXT: call void @_ZN6test111AD1Ev([[A]]* [[ELT]])
+
// CHECK: [[DONE:%.*]] = icmp eq [[A]]* [[ELT]], [[ARRAYBEGIN]]
// CHECK-NEXT: br i1 [[DONE]],
// - Next, chain to cleanup for single.
// CHECK: br label
// Finally, the cleanup for single.
- // CHECK: invoke void @_ZN6test111AD1Ev([[A]]* [[SINGLE]])
+
+ // CHECK98: invoke void @_ZN6test111AD1Ev([[A]]* [[SINGLE]])
+ // CHECK11: call void @_ZN6test111AD1Ev([[A]]* [[SINGLE]])
+
// CHECK: br label
// CHECK: resume
// (After this is a terminate landingpad.)
@@ -543,7 +589,9 @@ namespace test12 {
// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[PTR]] to [[A:%.*]]*
// CHECK-NEXT: invoke void @_ZN6test121AC1Ev([[A]]* [[CAST]])
// CHECK: ret [[A]]* [[CAST]]
- // CHECK: invoke void @_ZN6test121AdlEPvS1_(i8* [[PTR]], i8* [[PTR]])
+
+ // CHECK98: invoke void @_ZN6test121AdlEPvS1_(i8* [[PTR]], i8* [[PTR]])
+ // CHECK11: call void @_ZN6test121AdlEPvS1_(i8* [[PTR]], i8* [[PTR]])
}
-// CHECK: attributes [[NI_NR_NUW]] = { noinline noreturn nounwind }
+// CHECK98: attributes [[NI_NR_NUW]] = { noinline noreturn nounwind }
diff --git a/test/CodeGenCXX/goto.cpp b/test/CodeGenCXX/goto.cpp
index 27bd7affbac9..2f5b7197ca0e 100644
--- a/test/CodeGenCXX/goto.cpp
+++ b/test/CodeGenCXX/goto.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fcxx-exceptions -fexceptions -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fcxx-exceptions -fexceptions -emit-llvm -std=c++98 -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK98 %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fcxx-exceptions -fexceptions -emit-llvm -std=c++11 -o - | FileCheck -check-prefix=CHECK -check-prefix=CHECK11 %s
// Reduced from a crash on boost::interprocess's node_allocator_test.cpp.
namespace test0 {
@@ -24,7 +25,9 @@ namespace test0 {
// CHECK-NEXT: invoke void @_ZN5test01AC1Ev([[A]]* [[TMP]])
// CHECK: invoke void @_ZN5test01VC1ERKNS_1AE([[V]]* [[NEWCAST]], [[A]]* dereferenceable({{[0-9]+}}) [[TMP]])
// CHECK: store i1 false, i1* [[CLEANUPACTIVE]]
- // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[TMP]])
+
+ // CHECK98-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[TMP]])
+ // CHECK11-NEXT: call void @_ZN5test01AD1Ev([[A]]* [[TMP]])
A y;
try {
A z;
diff --git a/test/Driver/B-opt.c b/test/Driver/B-opt.c
index 318009413b1c..51273fd7b826 100644
--- a/test/Driver/B-opt.c
+++ b/test/Driver/B-opt.c
@@ -1,22 +1,22 @@
// Check -B driver option.
//
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
-// RUN: -B %S/Inputs/B_opt_tree/dir1 2>&1 \
+// RUN: -B %S/Inputs/B_opt_tree/dir1 -fuse-ld=ld 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-TRIPLE %s
// CHECK-B-OPT-TRIPLE: "{{.*}}/Inputs/B_opt_tree/dir1{{/|\\\\}}i386-unknown-linux-ld"
//
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
-// RUN: -B %S/Inputs/B_opt_tree/dir2 2>&1 \
+// RUN: -B %S/Inputs/B_opt_tree/dir2 -fuse-ld=ld 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-DIR %s
// CHECK-B-OPT-DIR: "{{.*}}/Inputs/B_opt_tree/dir2{{/|\\\\}}ld"
//
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
-// RUN: -B %S/Inputs/B_opt_tree/dir3/prefix- 2>&1 \
+// RUN: -B %S/Inputs/B_opt_tree/dir3/prefix- -fuse-ld=ld 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-PREFIX %s
// CHECK-B-OPT-PREFIX: "{{.*}}/Inputs/B_opt_tree/dir3{{/|\\\\}}prefix-ld"
//
// RUN: %clang %s -### -o %t.o -target i386-unknown-linux \
// RUN: -B %S/Inputs/B_opt_tree/dir3/prefix- \
-// RUN: -B %S/Inputs/B_opt_tree/dir2 2>&1 \
+// RUN: -B %S/Inputs/B_opt_tree/dir2 2>&1 -fuse-ld=ld \
// RUN: | FileCheck --check-prefix=CHECK-B-OPT-MULT %s
// CHECK-B-OPT-MULT: "{{.*}}/Inputs/B_opt_tree/dir3{{/|\\\\}}prefix-ld"
diff --git a/test/Driver/coverage-ld.c b/test/Driver/coverage-ld.c
index 1eda5f1e9593..206d9abec6fd 100644
--- a/test/Driver/coverage-ld.c
+++ b/test/Driver/coverage-ld.c
@@ -1,7 +1,7 @@
// Test coverage ld flags.
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux --coverage \
+// RUN: -target i386-unknown-linux --coverage -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LINUX-I386 %s
@@ -10,7 +10,7 @@
// CHECK-LINUX-I386: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.profile-i386.a" {{.*}} "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux --coverage \
+// RUN: -target x86_64-unknown-linux --coverage -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LINUX-X86-64 %s
@@ -19,7 +19,7 @@
// CHECK-LINUX-X86-64: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.profile-x86_64.a" {{.*}} "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-freebsd --coverage \
+// RUN: -target x86_64-unknown-freebsd --coverage -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_freebsd64_tree \
// RUN: | FileCheck --check-prefix=CHECK-FREEBSD-X86-64 %s
@@ -28,7 +28,7 @@
// CHECK-FREEBSD-X86-64: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}freebsd{{/|\\\\}}libclang_rt.profile-x86_64.a"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi --coverage \
+// RUN: -target arm-linux-androideabi --coverage -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-ARM %s
diff --git a/test/Driver/cross-linux.c b/test/Driver/cross-linux.c
index 3b1350489294..a5ea832e77ea 100644
--- a/test/Driver/cross-linux.c
+++ b/test/Driver/cross-linux.c
@@ -1,4 +1,4 @@
-// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \
// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
// RUN: --target=i386-unknown-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-I386 %s
@@ -6,7 +6,7 @@
// CHECK-I386: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/../../../../i386-unknown-linux-gnu/bin{{/|\\\\}}as" "--32"
// CHECK-I386: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/i386-unknown-linux-gnu/4.6.0/../../../../i386-unknown-linux-gnu/bin{{/|\\\\}}ld" {{.*}} "-m" "elf_i386"
//
-// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \
// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
// RUN: --target=x86_64-unknown-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-X86-64 %s
@@ -14,7 +14,7 @@
// CHECK-X86-64: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\\\}}as" "--64"
// CHECK-X86-64: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\\\}}ld" {{.*}} "-m" "elf_x86_64"
//
-// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \
// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
// RUN: --target=x86_64-unknown-linux-gnux32 \
// RUN: | FileCheck --check-prefix=CHECK-X32 %s
@@ -22,17 +22,17 @@
// CHECK-X32: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\\\}}as" "--x32"
// CHECK-X32: "{{.*}}/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../x86_64-unknown-linux-gnu/bin{{/|\\\\}}ld" {{.*}} "-m" "elf32_x86_64"
//
-// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \
// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
// RUN: --target=x86_64-unknown-linux-gnu -m32 \
// RUN: | FileCheck --check-prefix=CHECK-I386 %s
//
-// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \
// RUN: --gcc-toolchain=%S/Inputs/basic_cross_linux_tree/usr \
// RUN: --target=i386-unknown-linux-gnu -m64 \
// RUN: | FileCheck --check-prefix=CHECK-X86-64 %s
//
-// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \
// RUN: --gcc-toolchain=%S/Inputs/multilib_32bit_linux_tree/usr \
// RUN: --target=i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
@@ -49,7 +49,7 @@
// CHECK-MULTI32-I386: "-L[[sysroot]]/lib"
// CHECK-MULTI32-I386: "-L[[sysroot]]/usr/lib"
//
-// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \
// RUN: --gcc-toolchain=%S/Inputs/multilib_32bit_linux_tree/usr \
// RUN: --target=x86_64-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
@@ -67,7 +67,7 @@
// CHECK-MULTI32-X86-64: "-L[[sysroot]]/lib"
// CHECK-MULTI32-X86-64: "-L[[sysroot]]/usr/lib"
//
-// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \
// RUN: --gcc-toolchain=%S/Inputs/multilib_64bit_linux_tree/usr \
// RUN: --target=i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
@@ -85,7 +85,7 @@
// CHECK-MULTI64-I386: "-L[[sysroot]]/lib"
// CHECK-MULTI64-I386: "-L[[sysroot]]/usr/lib"
//
-// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as \
+// RUN: %clang -### -o %t %s 2>&1 -no-integrated-as -fuse-ld=ld \
// RUN: --gcc-toolchain=%S/Inputs/multilib_64bit_linux_tree/usr \
// RUN: --target=x86_64-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
diff --git a/test/Driver/fuchsia.c b/test/Driver/fuchsia.c
index 229b58828d0f..75172edf6b27 100644
--- a/test/Driver/fuchsia.c
+++ b/test/Driver/fuchsia.c
@@ -1,5 +1,5 @@
// RUN: %clang %s -### -no-canonical-prefixes --target=x86_64-unknown-fuchsia \
-// RUN: --sysroot=%S/platform 2>&1 | FileCheck %s
+// RUN: --sysroot=%S/platform -fuse-ld=ld 2>&1 | FileCheck %s
// CHECK: {{.*}}clang{{.*}}" "-cc1"
// CHECK: "-fuse-init-array"
// CHECK: "-isysroot" "[[SYSROOT:[^"]+]]"
diff --git a/test/Driver/fuchsia.cpp b/test/Driver/fuchsia.cpp
index 275891d52c30..4490f94d0715 100644
--- a/test/Driver/fuchsia.cpp
+++ b/test/Driver/fuchsia.cpp
@@ -1,5 +1,5 @@
// RUN: %clangxx %s -### -no-canonical-prefixes --target=x86_64-unknown-fuchsia \
-// RUN: --sysroot=%S/platform 2>&1 | FileCheck %s
+// RUN: --sysroot=%S/platform 2>&1 -fuse-ld=ld | FileCheck %s
// CHECK: {{.*}}clang{{.*}}" "-cc1"
// CHECK: "-fuse-init-array"
// CHECK: "-isysroot" "[[SYSROOT:[^"]+]]"
diff --git a/test/Driver/fuse-ld.c b/test/Driver/fuse-ld.c
index ca89eb997165..bd8c9a538624 100644
--- a/test/Driver/fuse-ld.c
+++ b/test/Driver/fuse-ld.c
@@ -32,7 +32,7 @@
-// RUN: %clang %s -### \
+// RUN: %clang %s -### -fuse-ld=ld \
// RUN: -target arm-linux-androideabi \
// RUN: -B%S/Inputs/basic_android_tree/bin 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-ANDROID-ARM-LD
@@ -50,7 +50,7 @@
// RUN: | FileCheck %s -check-prefix=CHECK-ANDROID-ARM-GOLD
// CHECK-ANDROID-ARM-GOLD: Inputs/basic_android_tree/bin{{/|\\+}}arm-linux-androideabi-ld.gold
-// RUN: %clang %s -### \
+// RUN: %clang %s -### -fuse-ld=ld \
// RUN: -target arm-linux-androideabi \
// RUN: -gcc-toolchain %S/Inputs/basic_android_tree 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-ANDROID-ARM-LD-TC
diff --git a/test/Driver/instrprof-ld.c b/test/Driver/instrprof-ld.c
index 05f65d614600..ea2010569975 100644
--- a/test/Driver/instrprof-ld.c
+++ b/test/Driver/instrprof-ld.c
@@ -1,7 +1,7 @@
// Test instrumented profiling ld flags.
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -fprofile-instr-generate \
+// RUN: -target i386-unknown-linux -fprofile-instr-generate -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LINUX-I386 %s
@@ -10,7 +10,7 @@
// CHECK-LINUX-I386: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.profile-i386.a" {{.*}} "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -fprofile-instr-generate \
+// RUN: -target x86_64-unknown-linux -fprofile-instr-generate -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LINUX-X86-64 %s
@@ -19,7 +19,7 @@
// CHECK-LINUX-X86-64: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.profile-x86_64.a" {{.*}} "-lc"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -fprofile-instr-generate -nostdlib \
+// RUN: -target x86_64-unknown-linux -fprofile-instr-generate -nostdlib -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LINUX-NOSTDLIB-X86-64 %s
@@ -28,7 +28,7 @@
// CHECK-LINUX-NOSTDLIB-X86-64: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.profile-x86_64.a"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-freebsd -fprofile-instr-generate \
+// RUN: -target x86_64-unknown-freebsd -fprofile-instr-generate -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_freebsd64_tree \
// RUN: | FileCheck --check-prefix=CHECK-FREEBSD-X86-64 %s
@@ -38,7 +38,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -shared \
-// RUN: -target i386-unknown-linux -fprofile-instr-generate \
+// RUN: -target i386-unknown-linux -fprofile-instr-generate -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LINUX-I386-SHARED %s
@@ -48,7 +48,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -shared \
-// RUN: -target x86_64-unknown-linux -fprofile-instr-generate \
+// RUN: -target x86_64-unknown-linux -fprofile-instr-generate -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LINUX-X86-64-SHARED %s
@@ -58,7 +58,7 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -shared \
-// RUN: -target x86_64-unknown-freebsd -fprofile-instr-generate \
+// RUN: -target x86_64-unknown-freebsd -fprofile-instr-generate -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_freebsd64_tree \
// RUN: | FileCheck --check-prefix=CHECK-FREEBSD-X86-64-SHARED %s
@@ -67,7 +67,7 @@
// CHECK-FREEBSD-X86-64-SHARED: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}freebsd{{/|\\\\}}libclang_rt.profile-x86_64.a"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-apple-darwin14 -fprofile-instr-generate \
+// RUN: -target x86_64-apple-darwin14 -fprofile-instr-generate -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: | FileCheck --check-prefix=CHECK-DARWIN-X86-64 %s
//
@@ -75,7 +75,7 @@
// CHECK-DARWIN-X86-64: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.profile_osx.a"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-apple-darwin14 -fprofile-instr-generate -nostdlib \
+// RUN: -target x86_64-apple-darwin14 -fprofile-instr-generate -nostdlib -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: | FileCheck --check-prefix=CHECK-DARWIN-NOSTDLIB-X86-64 %s
//
@@ -83,7 +83,7 @@
// CHECK-DARWIN-NOSTDLIB-X86-64: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.profile_osx.a"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm64-apple-ios -fprofile-instr-generate \
+// RUN: -target arm64-apple-ios -fprofile-instr-generate -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: | FileCheck --check-prefix=CHECK-DARWIN-ARM64 %s
//
@@ -91,7 +91,7 @@
// CHECK-DARWIN-ARM64: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.profile_ios.a"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target armv7-apple-darwin -mtvos-version-min=8.3 -fprofile-instr-generate \
+// RUN: -target armv7-apple-darwin -mtvos-version-min=8.3 -fprofile-instr-generate -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: | FileCheck --check-prefix=CHECK-TVOS-ARMV7 %s
//
@@ -99,7 +99,7 @@
// CHECK-TVOS-ARMV7: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.profile_tvos.a"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target armv7s-apple-darwin10 -mwatchos-version-min=2.0 -arch armv7k -fprofile-instr-generate \
+// RUN: -target armv7s-apple-darwin10 -mwatchos-version-min=2.0 -arch armv7k -fprofile-instr-generate -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: | FileCheck --check-prefix=CHECK-WATCHOS-ARMV7 %s
//
diff --git a/test/Driver/mips-mti-linux.c b/test/Driver/mips-mti-linux.c
index 4835d798c269..91a63e2f23cf 100644
--- a/test/Driver/mips-mti-linux.c
+++ b/test/Driver/mips-mti-linux.c
@@ -8,7 +8,7 @@
// = Big-endian, mips32r2, hard float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: --target=mips-mti-linux -mips32r2 -mhard-float -rtlib=platform \
+// RUN: --target=mips-mti-linux -mips32r2 -mhard-float -rtlib=platform -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/mips_mti_linux/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-BE-HF-32R2 %s
//
@@ -26,7 +26,7 @@
// = Little-endian, mips32r2, hard float
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: --target=mips-mti-linux -mips32r2 -EL -mhard-float -rtlib=platform \
+// RUN: --target=mips-mti-linux -mips32r2 -EL -mhard-float -rtlib=platform -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/mips_mti_linux/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-LE-HF-32R2 %s
//
diff --git a/test/Driver/netbsd.c b/test/Driver/netbsd.c
index 1a87d8e1a6a9..5558a80b9860 100644
--- a/test/Driver/netbsd.c
+++ b/test/Driver/netbsd.c
@@ -23,6 +23,12 @@
// RUN: %clang -no-canonical-prefixes -target aarch64--netbsd7.0.0 \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=AARCH64-7 %s
+// RUN: %clang -no-canonical-prefixes -target aarch64_be--netbsd \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=AARCH64_BE %s
+// RUN: %clang -no-canonical-prefixes -target aarch64_be--netbsd7.0.0 \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=AARCH64_BE-7 %s
// RUN: %clang -no-canonical-prefixes -target arm--netbsd-eabi \
// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=ARM %s
@@ -84,6 +90,12 @@
// RUN: %clang -no-canonical-prefixes -target aarch64--netbsd7.0.0 -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-AARCH64-7 %s
+// RUN: %clang -no-canonical-prefixes -target aarch64_be--netbsd -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-AARCH64_BE %s
+// RUN: %clang -no-canonical-prefixes -target aarch64_be--netbsd7.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-AARCH64_BE-7 %s
// RUN: %clang -no-canonical-prefixes -target arm--netbsd-eabi -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-ARM %s
@@ -171,6 +183,18 @@
// AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// AARCH64_BE: clang{{.*}}" "-cc1" "-triple" "aarch64_be--netbsd"
+// AARCH64_BE: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// AARCH64_BE: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// AARCH64_BE-7: clang{{.*}}" "-cc1" "-triple" "aarch64_be--netbsd7.0.0"
+// AARCH64_BE-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// AARCH64_BE-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// ARM: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd-eabi"
// ARM: as{{.*}}" "-mcpu=arm926ej-s" "-o"
// ARM: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
@@ -311,6 +335,18 @@
// S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// S-AARCH64_BE: clang{{.*}}" "-cc1" "-triple" "aarch64_be--netbsd"
+// S-AARCH64_BE: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-AARCH64_BE: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-AARCH64_BE-7: clang{{.*}}" "-cc1" "-triple" "aarch64_be--netbsd7.0.0"
+// S-AARCH64_BE-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-AARCH64_BE-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// S-ARM: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd-eabi"
// S-ARM: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-ARM: "-m" "armelf_nbsd_eabi"
diff --git a/test/Driver/netbsd.cpp b/test/Driver/netbsd.cpp
index 104d03eba191..e9b1759831b2 100644
--- a/test/Driver/netbsd.cpp
+++ b/test/Driver/netbsd.cpp
@@ -19,6 +19,12 @@
// RUN: %clangxx -no-canonical-prefixes -target aarch64--netbsd7.0.0 \
// RUN: -stdlib=platform --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=AARCH64-7 %s
+// RUN: %clangxx -no-canonical-prefixes -target aarch64_be--netbsd \
+// RUN: -stdlib=platform --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=AARCH64_BE %s
+// RUN: %clangxx -no-canonical-prefixes -target aarch64_be--netbsd7.0.0 \
+// RUN: -stdlib=platform --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=AARCH64_BE-7 %s
// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd \
// RUN: -stdlib=platform --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=SPARC %s
@@ -65,6 +71,12 @@
// RUN: %clangxx -no-canonical-prefixes -target aarch64--netbsd7.0.0 -static \
// RUN: -stdlib=platform --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-AARCH64-7 %s
+// RUN: %clangxx -no-canonical-prefixes -target aarch64_be--netbsd -static \
+// RUN: -stdlib=platform --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-AARCH64_BE %s
+// RUN: %clangxx -no-canonical-prefixes -target aarch64_be--netbsd7.0.0 -static \
+// RUN: -stdlib=platform --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-AARCH64_BE-7 %s
// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd -static \
// RUN: -stdlib=platform --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-SPARC %s
@@ -136,6 +148,20 @@
// AARCH64-7: "-lm" "-lc"
// AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// AARCH64_BE: clang{{.*}}" "-cc1" "-triple" "aarch64_be--netbsd"
+// AARCH64_BE: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// AARCH64_BE: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// AARCH64_BE: "-lm" "-lc"
+// AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// AARCH64_BE-7: clang{{.*}}" "-cc1" "-triple" "aarch64_be--netbsd7.0.0"
+// AARCH64_BE-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// AARCH64_BE-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// AARCH64_BE-7: "-lm" "-lc"
+// AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// SPARC: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd"
// SPARC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
@@ -241,6 +267,20 @@
// S-AARCH64-7: "-lm" "-lc"
// S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// S-AARCH64_BE: clang{{.*}}" "-cc1" "-triple" "aarch64_be--netbsd"
+// S-AARCH64_BE: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-AARCH64_BE: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-AARCH64_BE: "-lm" "-lc"
+// S-AARCH64_BE: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-AARCH64_BE-7: clang{{.*}}" "-cc1" "-triple" "aarch64_be--netbsd7.0.0"
+// S-AARCH64_BE-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-AARCH64_BE-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-AARCH64_BE-7: "-lm" "-lc"
+// S-AARCH64_BE-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// S-SPARC: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd"
// S-SPARC: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
diff --git a/test/Driver/nostdlib.c b/test/Driver/nostdlib.c
index 7269312acba9..a9ef665c5744 100644
--- a/test/Driver/nostdlib.c
+++ b/test/Driver/nostdlib.c
@@ -13,12 +13,12 @@
// In the presence of -nostdlib, the standard libraries should not be
// passed down to link line
// RUN: %clang -no-canonical-prefixes %s -### -Wno-liblto -o %t.o 2>&1 \
-// RUN: -target i686-pc-linux-gnu -nostdlib --rtlib=compiler-rt \
+// RUN: -target i686-pc-linux-gnu -nostdlib --rtlib=compiler-rt -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir -lclang_rt.builtins-i686 \
// RUN: | FileCheck --check-prefix=CHECK-LINUX-NOSTDLIB %s
//
// RUN: %clang -no-canonical-prefixes %s -### -Wno-liblto -o %t.o 2>&1 \
-// RUN: -target i686-pc-linux-gnu --rtlib=compiler-rt -nostdlib \
+// RUN: -target i686-pc-linux-gnu --rtlib=compiler-rt -nostdlib -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir -lclang_rt.builtins-i686 \
// RUN: | FileCheck --check-prefix=CHECK-LINUX-NOSTDLIB %s
//
diff --git a/test/Driver/prefixed-tools.c b/test/Driver/prefixed-tools.c
index cdd59dae133d..63f7f29ae963 100644
--- a/test/Driver/prefixed-tools.c
+++ b/test/Driver/prefixed-tools.c
@@ -1,8 +1,8 @@
-// RUN: %clang -### -B%S/Inputs/prefixed_tools_tree -o %t.o -no-integrated-as \
+// RUN: %clang -### -B%S/Inputs/prefixed_tools_tree -o %t.o -no-integrated-as -fuse-ld=ld \
// RUN: -target x86_64--linux %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-M64 %s
-// RUN: %clang -### -B%S/Inputs/prefixed_tools_tree -o %t.o -no-integrated-as \
+// RUN: %clang -### -B%S/Inputs/prefixed_tools_tree -o %t.o -no-integrated-as -fuse-ld=ld \
// RUN: -m32 -target x86_64--linux %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-M32 %s
diff --git a/test/Driver/sanitizer-ld.c b/test/Driver/sanitizer-ld.c
index 91798b91b343..c98ce8a0c4c7 100644
--- a/test/Driver/sanitizer-ld.c
+++ b/test/Driver/sanitizer-ld.c
@@ -1,7 +1,7 @@
// Test sanitizers ld flags.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -fsanitize=address \
+// RUN: -target i386-unknown-linux -fuse-ld=ld -fsanitize=address \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-LINUX %s
@@ -17,7 +17,7 @@
// CHECK-ASAN-LINUX: "-ldl"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -fsanitize=address -shared-libasan \
+// RUN: -target i386-unknown-linux -fuse-ld=ld -fsanitize=address -shared-libasan \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-SHARED-ASAN-LINUX %s
@@ -34,7 +34,7 @@
// CHECK-SHARED-ASAN-LINUX-NOT: "--dynamic-list"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.so -shared 2>&1 \
-// RUN: -target i386-unknown-linux -fsanitize=address -shared-libasan \
+// RUN: -target i386-unknown-linux -fuse-ld=ld -fsanitize=address -shared-libasan \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-DSO-SHARED-ASAN-LINUX %s
@@ -51,7 +51,7 @@
// CHECK-DSO-SHARED-ASAN-LINUX-NOT: "--dynamic-list"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-freebsd -fsanitize=address \
+// RUN: -target i386-unknown-freebsd -fuse-ld=ld -fsanitize=address \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_freebsd_tree \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-FREEBSD %s
@@ -67,7 +67,7 @@
// CHECK-ASAN-FREEBSD: "-lrt"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-freebsd -fsanitize=address \
+// RUN: -target i386-unknown-freebsd -fuse-ld=ld -fsanitize=address \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_freebsd_tree \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-FREEBSD-LDL %s
@@ -76,7 +76,7 @@
// CHECK-ASAN-FREEBSD-LDL-NOT: "-ldl"
// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -stdlib=platform -fsanitize=address \
+// RUN: -target i386-unknown-linux -fuse-ld=ld -stdlib=platform -fsanitize=address \
// RUN: -resource-dir=%S/Inputs/empty_resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-LINUX-CXX %s
@@ -93,7 +93,7 @@
// CHECK-ASAN-LINUX-CXX: "-ldl"
// RUN: %clang -no-canonical-prefixes %s -### -o /dev/null -fsanitize=address \
-// RUN: -target i386-unknown-linux -stdlib=platform \
+// RUN: -target i386-unknown-linux -fuse-ld=ld -stdlib=platform \
// RUN: --sysroot=%S/Inputs/basic_linux_tree -lstdc++ -static 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-LINUX-CXX-STATIC %s
//
@@ -103,7 +103,7 @@
// CHECK-ASAN-LINUX-CXX-STATIC: stdc++
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-gnueabi -fsanitize=address \
+// RUN: -target arm-linux-gnueabi -fuse-ld=ld -fsanitize=address \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-ARM %s
//
@@ -112,7 +112,7 @@
// CHECK-ASAN-ARM: libclang_rt.asan-arm.a"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target armv7l-linux-gnueabi -fsanitize=address \
+// RUN: -target armv7l-linux-gnueabi -fuse-ld=ld -fsanitize=address \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-ARMv7 %s
//
@@ -121,7 +121,7 @@
// CHECK-ASAN-ARMv7: libclang_rt.asan-arm.a"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi -fsanitize=address \
+// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=address \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-ANDROID %s
//
@@ -141,7 +141,7 @@
// CHECK-ASAN-ANDROID-SHARED-LIBASAN-NOT: argument unused during compilation: '-shared-libasan'
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi -fsanitize=address \
+// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=address \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-ANDROID-SHARED %s
@@ -152,7 +152,7 @@
// CHECK-ASAN-ANDROID-SHARED-NOT: "-lpthread"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target sparcel-myriad-rtems-elf -fsanitize=address \
+// RUN: -target sparcel-myriad-rtems-elf -fuse-ld=ld -fsanitize=address \
// RUN: --sysroot=%S/Inputs/basic_myriad_tree \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-MYRIAD %s
//
@@ -161,7 +161,7 @@
// CHECK-ASAN-MYRIAD: libclang_rt.asan-sparcel.a"
// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -stdlib=platform -lstdc++ \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld -stdlib=platform -lstdc++ \
// RUN: -fsanitize=thread \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
@@ -180,7 +180,7 @@
// CHECK-TSAN-LINUX-CXX: "-ldl"
// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -stdlib=platform -lstdc++ \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld -stdlib=platform -lstdc++ \
// RUN: -fsanitize=memory \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
@@ -199,7 +199,7 @@
// CHECK-MSAN-LINUX-CXX: "-ldl"
// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux \
+// RUN: -target i386-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX %s
// CHECK-UBSAN-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -220,7 +220,7 @@
// CHECK-UBSAN-LINUX-LINK-CXX-NOT: "-lstdc++"
// RUN: %clangxx -fsanitize=undefined %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -stdlib=platform \
+// RUN: -target i386-unknown-linux -fuse-ld=ld -stdlib=platform \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX-CXX %s
@@ -235,7 +235,7 @@
// CHECK-UBSAN-LINUX-CXX: "-lpthread"
// RUN: %clang -fsanitize=address,undefined %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux \
+// RUN: -target i386-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-UBSAN-LINUX %s
// CHECK-ASAN-UBSAN-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -245,7 +245,7 @@
// CHECK-ASAN-UBSAN-LINUX: "-lpthread"
// RUN: %clangxx -fsanitize=address,undefined %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux -stdlib=platform \
+// RUN: -target i386-unknown-linux -fuse-ld=ld -stdlib=platform \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-UBSAN-LINUX-CXX %s
// CHECK-ASAN-UBSAN-LINUX-CXX: "{{.*}}ld{{(.exe)?}}"
@@ -256,7 +256,7 @@
// CHECK-ASAN-UBSAN-LINUX-CXX: "-lpthread"
// RUN: %clangxx -fsanitize=memory,undefined %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-MSAN-UBSAN-LINUX-CXX %s
// CHECK-MSAN-UBSAN-LINUX-CXX: "{{.*}}ld{{(.exe)?}}"
@@ -264,7 +264,7 @@
// CHECK-MSAN-UBSAN-LINUX-CXX-NOT: libclang_rt.ubsan
// RUN: %clangxx -fsanitize=thread,undefined %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-TSAN-UBSAN-LINUX-CXX %s
// CHECK-TSAN-UBSAN-LINUX-CXX: "{{.*}}ld{{(.exe)?}}"
@@ -272,7 +272,7 @@
// CHECK-TSAN-UBSAN-LINUX-CXX-NOT: libclang_rt.ubsan
// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
-// RUN: -target i386-unknown-linux \
+// RUN: -target i386-unknown-linux -fuse-ld=ld \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: -shared \
@@ -283,7 +283,7 @@
// CHECK-UBSAN-LINUX-SHARED-NOT: libclang_rt.ubsan
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -fsanitize=leak \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld -fsanitize=leak \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LSAN-LINUX %s
//
@@ -295,7 +295,7 @@
// CHECK-LSAN-LINUX: "-ldl"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -fsanitize=leak -fsanitize-coverage=func \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld -fsanitize=leak -fsanitize-coverage=func \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LSAN-COV-LINUX %s
//
@@ -308,7 +308,7 @@
// CHECK-LSAN-COV-LINUX: "-ldl"
// RUN: %clang -fsanitize=leak,address %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LSAN-ASAN-LINUX %s
// CHECK-LSAN-ASAN-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -317,7 +317,7 @@
// CHECK-LSAN-ASAN-LINUX-NOT: libclang_rt.lsan
// RUN: %clang -fsanitize=address -fsanitize-coverage=func %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-COV-LINUX %s
// CHECK-ASAN-COV-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -327,7 +327,7 @@
// CHECK-ASAN-COV-LINUX: "-lpthread"
// RUN: %clang -fsanitize=memory -fsanitize-coverage=func %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-MSAN-COV-LINUX %s
// CHECK-MSAN-COV-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -337,7 +337,7 @@
// CHECK-MSAN-COV-LINUX: "-lpthread"
// RUN: %clang -fsanitize=dataflow -fsanitize-coverage=func %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-DFSAN-COV-LINUX %s
// CHECK-DFSAN-COV-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -347,7 +347,7 @@
// CHECK-DFSAN-COV-LINUX: "-lpthread"
// RUN: %clang -fsanitize=undefined -fsanitize-coverage=func %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBSAN-COV-LINUX %s
// CHECK-UBSAN-COV-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -356,7 +356,7 @@
// CHECK-UBSAN-COV-LINUX: "-lpthread"
// RUN: %clang -fsanitize-coverage=func %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-COV-LINUX %s
// CHECK-COV-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -366,7 +366,7 @@
// CFI by itself does not link runtime libraries.
// RUN: %clang -fsanitize=cfi %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -rtlib=platform \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld -rtlib=platform \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-LINUX %s
// CHECK-CFI-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -375,7 +375,7 @@
// CFI with diagnostics links the UBSan runtime.
// RUN: %clang -fsanitize=cfi -fno-sanitize-trap=cfi -fsanitize-recover=cfi \
// RUN: %s -### -o %t.o 2>&1\
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-DIAG-LINUX %s
// CHECK-CFI-DIAG-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -383,7 +383,7 @@
// Cross-DSO CFI links the CFI runtime.
// RUN: %clang -fsanitize=cfi -fsanitize-cfi-cross-dso %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-CROSS-DSO-LINUX %s
// CHECK-CFI-CROSS-DSO-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -393,7 +393,7 @@
// Cross-DSO CFI with diagnostics links just the CFI runtime.
// RUN: %clang -fsanitize=cfi -fsanitize-cfi-cross-dso %s -### -o %t.o 2>&1 \
// RUN: -fno-sanitize-trap=cfi -fsanitize-recover=cfi \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-CROSS-DSO-DIAG-LINUX %s
// CHECK-CFI-CROSS-DSO-DIAG-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -402,7 +402,7 @@
// RUN: %clangxx -fsanitize=address %s -### -o %t.o 2>&1 \
// RUN: -mmacosx-version-min=10.6 \
-// RUN: -target x86_64-apple-darwin13.4.0 -stdlib=platform \
+// RUN: -target x86_64-apple-darwin13.4.0 -fuse-ld=ld -stdlib=platform \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-DARWIN106-CXX %s
// CHECK-ASAN-DARWIN106-CXX: "{{.*}}ld{{(.exe)?}}"
@@ -410,7 +410,7 @@
// CHECK-ASAN-DARWIN106-CXX-NOT: -lc++abi
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux -fsanitize=safe-stack \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld -fsanitize=safe-stack \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-SAFESTACK-LINUX %s
//
@@ -421,7 +421,7 @@
// CHECK-SAFESTACK-LINUX: "-ldl"
// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-LINUX %s
// CHECK-CFI-STATS-LINUX: "{{.*}}ld{{(.exe)?}}"
@@ -430,7 +430,7 @@
// CHECK-CFI-STATS-LINUX: "{{[^"]*}}libclang_rt.stats-x86_64.a"
// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-apple-darwin \
+// RUN: -target x86_64-apple-darwin -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-DARWIN %s
// CHECK-CFI-STATS-DARWIN: "{{.*}}ld{{(.exe)?}}"
@@ -454,7 +454,7 @@
// CHECK-CFI-STATS-WIN32: "--linker-option=/include:___sanitizer_stats_register"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi -fsanitize=safe-stack \
+// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=safe-stack \
// RUN: --sysroot=%S/Inputs/basic_android_tree \
// RUN: | FileCheck --check-prefix=CHECK-SAFESTACK-ANDROID-ARM %s
//
@@ -462,7 +462,7 @@
// CHECK-SAFESTACK-ANDROID-ARM-NOT: libclang_rt.safestack
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o -shared 2>&1 \
-// RUN: -target arm-linux-androideabi -fsanitize=safe-stack \
+// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=safe-stack \
// RUN: --sysroot=%S/Inputs/basic_android_tree \
// RUN: | FileCheck --check-prefix=CHECK-SAFESTACK-SHARED-ANDROID-ARM %s
//
@@ -470,7 +470,7 @@
// CHECK-SAFESTACK-SHARED-ANDROID-ARM-NOT: libclang_rt.safestack
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target aarch64-linux-android -fsanitize=safe-stack \
+// RUN: -target aarch64-linux-android -fuse-ld=ld -fsanitize=safe-stack \
// RUN: --sysroot=%S/Inputs/basic_android_tree \
// RUN: | FileCheck --check-prefix=CHECK-SAFESTACK-ANDROID-AARCH64 %s
//
@@ -478,7 +478,7 @@
// CHECK-SAFESTACK-ANDROID-AARCH64-NOT: libclang_rt.safestack
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi -fsanitize=cfi \
+// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=cfi \
// RUN: --sysroot=%S/Inputs/basic_android_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-ANDROID %s
//
@@ -487,7 +487,7 @@
// CHECK-CFI-ANDROID-NOT: __cfi_check
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi -fsanitize=cfi \
+// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=cfi \
// RUN: -fsanitize-cfi-cross-dso \
// RUN: --sysroot=%S/Inputs/basic_android_tree \
// RUN: | FileCheck --check-prefix=CHECK-CROSSDSO-CFI-ANDROID %s
@@ -498,31 +498,31 @@
// CHECK-CROSSDSO-CFI-ANDROID-NOT: libclang_rt.cfi
// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-scei-ps4 \
+// RUN: -target x86_64-scei-ps4 -fuse-ld=ld \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-UBSAN-PS4 %s
// CHECK-UBSAN-PS4: "{{.*}}ld{{(.gold)?(.exe)?}}"
// CHECK-UBSAN-PS4: -lSceDbgUBSanitizer_stub_weak
// RUN: %clang -fsanitize=address %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-scei-ps4 \
+// RUN: -target x86_64-scei-ps4 -fuse-ld=ld \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-PS4 %s
// CHECK-ASAN-PS4: "{{.*}}ld{{(.gold)?(.exe)?}}"
// CHECK-ASAN-PS4: -lSceDbgAddressSanitizer_stub_weak
// RUN: %clang -fsanitize=address,undefined %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-scei-ps4 \
+// RUN: -target x86_64-scei-ps4 -fuse-ld=ld \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-AUBSAN-PS4 %s
// CHECK-AUBSAN-PS4: "{{.*}}ld{{(.gold)?(.exe)?}}"
// CHECK-AUBSAN-PS4: -lSceDbgAddressSanitizer_stub_weak
// RUN: %clang -fsanitize=efficiency-cache-frag %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: | FileCheck --check-prefix=CHECK-ESAN-LINUX %s
// RUN: %clang -fsanitize=efficiency-working-set %s -### -o %t.o 2>&1 \
-// RUN: -target x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux -fuse-ld=ld \
// RUN: | FileCheck --check-prefix=CHECK-ESAN-LINUX %s
//
// CHECK-ESAN-LINUX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
diff --git a/test/Driver/windows-cross.c b/test/Driver/windows-cross.c
index 84ef2df75d6f..5a2fe52b099e 100644
--- a/test/Driver/windows-cross.c
+++ b/test/Driver/windows-cross.c
@@ -1,34 +1,34 @@
-// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -stdlib=libstdc++ -rtlib=platform -o /dev/null %s 2>&1 \
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -stdlib=libstdc++ -rtlib=platform -o /dev/null %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-BASIC
// CHECK-BASIC: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/gcc" "{{.*}}.o" "-lmsvcrt" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
-// RUN: %clang -### -target armv7-windows-itanium --sysroot %s/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -rtlib=compiler-rt -stdlib=libstdc++ -o /dev/null %s 2>&1 \
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %s/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -rtlib=compiler-rt -stdlib=libstdc++ -o /dev/null %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-RTLIB
// CHECK-RTLIB: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib" "-L{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/gcc" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
-// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -rtlib=compiler-rt -stdlib=libc++ -o /dev/null %s 2>&1 \
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -rtlib=compiler-rt -stdlib=libc++ -o /dev/null %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-C-LIBCXX
// CHECK-C-LIBCXX: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
-// RUN: %clangxx -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -rtlib=compiler-rt -stdlib=libc++ -o /dev/null %s 2>&1 \
+// RUN: %clangxx -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -rtlib=compiler-rt -stdlib=libc++ -o /dev/null %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-LIBCXX
// CHECK-LIBCXX: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbegin.obj" "{{.*}}.o" "-lc++" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
-// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -shared -rtlib=compiler-rt -stdlib=libc++ -o shared.dll %s 2>&1 \
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -shared -rtlib=compiler-rt -stdlib=libc++ -o shared.dll %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-SHARED
// CHECK-SHARED: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-shared" "-Bdynamic" "--enable-auto-image-base" "--entry" "_DllMainCRTStartup" "--allow-multiple-definition" "-o" "shared.dll" "--out-implib" "shared.lib" "{{.*}}/Inputs/Windows/ARM/8.1/usr/lib/crtbeginS.obj" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
-// RUN: %clang -### -target armv7-windows-itanium --sysroot %s/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -shared -rtlib=compiler-rt -stdlib=libc++ -nostartfiles -o shared.dll %s 2>&1 \
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %s/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -shared -rtlib=compiler-rt -stdlib=libc++ -nostartfiles -o shared.dll %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-NOSTARTFILES
// CHECK-NOSTARTFILES: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-shared" "-Bdynamic" "--enable-auto-image-base" "--entry" "_DllMainCRTStartup" "--allow-multiple-definition" "-o" "shared.dll" "--out-implib" "shared.lib" "{{.*}}.o" "-lmsvcrt" "{{.*[\\/]}}clang_rt.builtins-arm.lib"
-// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -shared -rtlib=compiler-rt -stdlib=libc++ -nostartfiles -nodefaultlibs -o shared.dll %s 2>&1 \
+// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=ld -shared -rtlib=compiler-rt -stdlib=libc++ -nostartfiles -nodefaultlibs -o shared.dll %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-STANDALONE
// CHECK-STANDALONE: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-shared" "-Bdynamic" "--enable-auto-image-base" "--entry" "_DllMainCRTStartup" "--allow-multiple-definition" "-o" "shared.dll" "--out-implib" "shared.lib" "{{.*}}.o"
diff --git a/test/Index/Core/index-source.cpp b/test/Index/Core/index-source.cpp
index 7db5d531f43d..0e898d8c83ab 100644
--- a/test/Index/Core/index-source.cpp
+++ b/test/Index/Core/index-source.cpp
@@ -1,5 +1,16 @@
// RUN: c-index-test core -print-source-symbols -- %s -std=c++14 -target x86_64-apple-macosx10.7 | FileCheck %s
+// CHECK: [[@LINE+1]]:7 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Def | rel: 0
+class Cls {
+ // CHECK: [[@LINE+2]]:3 | constructor/C++ | Cls | c:@S@Cls@F@Cls#I# | __ZN3ClsC1Ei | Decl,RelChild | rel: 1
+ // CHECK-NEXT: RelChild | Cls | c:@S@Cls
+ Cls(int x);
+ // CHECK: [[@LINE+1]]:3 | constructor/cxx-copy-ctor/C++ | Cls | c:@S@Cls@F@Cls#&1$@S@Cls# | __ZN3ClsC1ERKS_ | Decl,RelChild | rel: 1
+ Cls(const Cls &);
+ // CHECK: [[@LINE+1]]:3 | constructor/cxx-move-ctor/C++ | Cls | c:@S@Cls@F@Cls#&&$@S@Cls# | __ZN3ClsC1EOS_ | Decl,RelChild | rel: 1
+ Cls(Cls &&);
+};
+
template <typename TemplArg>
class TemplCls {
// CHECK: [[@LINE-1]]:7 | class(Gen)/C++ | TemplCls | c:@ST>1#T@TemplCls | <no-cgname> | Def | rel: 0
diff --git a/test/Misc/diag-template-diffing.cpp b/test/Misc/diag-template-diffing.cpp
index 780839899282..9006fc6f9ac9 100644
--- a/test/Misc/diag-template-diffing.cpp
+++ b/test/Misc/diag-template-diffing.cpp
@@ -1265,7 +1265,7 @@ void test() {
foo<BoolT<true>>(X);
}
// CHECK-ELIDE-NOTREE: no matching function for call to 'foo'
-// CHECK-ELIDE-NOTREE: candidate function [with T = BoolArgumentBitExtended::BoolT<true>] not viable: no known conversion from 'BoolT<false>' to 'BoolT<true>' for 1st argument
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'BoolT<false>' to 'BoolT<true>' for 1st argument
}
namespace DifferentIntegralTypes {
@@ -1401,7 +1401,7 @@ void run() {
f(1, integral_constant<bool, true>{});
}
// CHECK-ELIDE-NOTREE: error: no matching function for call to 'f'
-// CHECK-ELIDE-NOTREE: note: candidate function [with T = int] not viable: no known conversion from 'integral_constant<[...], true>' to 'integral_constant<[...], false>' for 2nd argument
+// CHECK-ELIDE-NOTREE: note: candidate function not viable: no known conversion from 'integral_constant<[...], true>' to 'integral_constant<[...], false>' for 2nd argument
}
namespace ZeroArgs {
@@ -1454,7 +1454,7 @@ void run() {
D<X::X1>(VectorType<X::X2>());
}
// CHECK-ELIDE-NOTREE: error: no matching function for call to 'D'
-// CHECK-ELIDE-NOTREE: note: candidate function [with x = TypeAlias::X::X1] not viable: no known conversion from 'VectorType<X::X2>' to 'const VectorType<(TypeAlias::X)0>' for 1st argument
+// CHECK-ELIDE-NOTREE: note: candidate function not viable: no known conversion from 'VectorType<X::X2>' to 'const VectorType<(TypeAlias::X)0>' for 1st argument
}
namespace TypeAlias2 {
diff --git a/test/Modules/Inputs/pch-with-module-name/A.h b/test/Modules/Inputs/pch-with-module-name/A.h
new file mode 100644
index 000000000000..a73b3759d4ec
--- /dev/null
+++ b/test/Modules/Inputs/pch-with-module-name/A.h
@@ -0,0 +1 @@
+// in pch
diff --git a/test/Modules/Inputs/pch-with-module-name/C.h b/test/Modules/Inputs/pch-with-module-name/C.h
new file mode 100644
index 000000000000..f681dd80974a
--- /dev/null
+++ b/test/Modules/Inputs/pch-with-module-name/C.h
@@ -0,0 +1 @@
+#include "D.h"
diff --git a/test/Modules/Inputs/pch-with-module-name/C.m b/test/Modules/Inputs/pch-with-module-name/C.m
new file mode 100644
index 000000000000..90fe1bcc5851
--- /dev/null
+++ b/test/Modules/Inputs/pch-with-module-name/C.m
@@ -0,0 +1 @@
+//empty
diff --git a/test/Modules/Inputs/pch-with-module-name/D.h b/test/Modules/Inputs/pch-with-module-name/D.h
new file mode 100644
index 000000000000..90fe1bcc5851
--- /dev/null
+++ b/test/Modules/Inputs/pch-with-module-name/D.h
@@ -0,0 +1 @@
+//empty
diff --git a/test/Modules/Inputs/pch-with-module-name/module.modulemap b/test/Modules/Inputs/pch-with-module-name/module.modulemap
new file mode 100644
index 000000000000..379b0d48d589
--- /dev/null
+++ b/test/Modules/Inputs/pch-with-module-name/module.modulemap
@@ -0,0 +1,9 @@
+module CloudKit {
+ header "C.h"
+ export *
+}
+
+module Contacts {
+ header "D.h"
+ export *
+}
diff --git a/test/Modules/Inputs/pch-with-module-name/test.h b/test/Modules/Inputs/pch-with-module-name/test.h
new file mode 100644
index 000000000000..7a13ba4d72d4
--- /dev/null
+++ b/test/Modules/Inputs/pch-with-module-name/test.h
@@ -0,0 +1 @@
+#include "A.h"
diff --git a/test/Modules/pch-with-module-name.m b/test/Modules/pch-with-module-name.m
new file mode 100644
index 000000000000..c4096308c4f6
--- /dev/null
+++ b/test/Modules/pch-with-module-name.m
@@ -0,0 +1,5 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs/pch-with-module-name -emit-pch -o %t-A.pch %S/Inputs/pch-with-module-name/test.h -fmodule-name=Contacts -x objective-c-header
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs/pch-with-module-name -include-pch %t-A.pch %s -fsyntax-only -fmodule-name=Contacts -verify
+// expected-no-diagnostics
+#include "C.h"
diff --git a/test/OpenMP/atomic_codegen.cpp b/test/OpenMP/atomic_codegen.cpp
index 536f2cdffafb..7f62a9bfa6fb 100644
--- a/test/OpenMP/atomic_codegen.cpp
+++ b/test/OpenMP/atomic_codegen.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -x c++ -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -x c++ -emit-llvm -std=c++98 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -x c++ -emit-llvm -std=c++11 %s -o - | FileCheck %s
// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG
// expected-no-diagnostics
@@ -21,14 +23,15 @@ void parallel_atomic_ewc() {
// CHECK: [[SCALAR_ADDR:%.+]] = invoke dereferenceable(4) i32* @_ZN2St3getEv(%struct.St* [[TEMP_ST_ADDR]])
// CHECK: [[SCALAR_VAL:%.+]] = load atomic i32, i32* [[SCALAR_ADDR]] monotonic
// CHECK: store i32 [[SCALAR_VAL]], i32* @b
- // CHECK: invoke void @_ZN2StD1Ev(%struct.St* [[TEMP_ST_ADDR]])
+ // CHECK98: invoke void @_ZN2StD1Ev(%struct.St* [[TEMP_ST_ADDR]])
+ // CHECK11: call void @_ZN2StD1Ev(%struct.St* [[TEMP_ST_ADDR]])
#pragma omp atomic read
b = St().get();
// CHECK-DAG: invoke void @_ZN2StC1Ev(%struct.St* [[TEMP_ST_ADDR:%.+]])
// CHECK-DAG: [[SCALAR_ADDR:%.+]] = invoke dereferenceable(4) i32* @_ZN2St3getEv(%struct.St* [[TEMP_ST_ADDR]])
// CHECK-DAG: [[B_VAL:%.+]] = load i32, i32* @b
// CHECK: store atomic i32 [[B_VAL]], i32* [[SCALAR_ADDR]] monotonic
- // CHECK: invoke void @_ZN2StD1Ev(%struct.St* [[TEMP_ST_ADDR]])
+ // CHECK: {{invoke|call}} void @_ZN2StD1Ev(%struct.St* [[TEMP_ST_ADDR]])
#pragma omp atomic write
St().get() = b;
// CHECK: invoke void @_ZN2StC1Ev(%struct.St* [[TEMP_ST_ADDR:%.+]])
@@ -46,7 +49,7 @@ void parallel_atomic_ewc() {
// CHECK: [[COND:%.+]] = extractvalue { i32, i1 } [[RES]], 1
// CHECK: br i1 [[COND]], label %[[OMP_DONE:.+]], label %[[OMP_UPDATE]]
// CHECK: [[OMP_DONE]]
- // CHECK: invoke void @_ZN2StD1Ev(%struct.St* [[TEMP_ST_ADDR]])
+ // CHECK: {{invoke|call}} void @_ZN2StD1Ev(%struct.St* [[TEMP_ST_ADDR]])
#pragma omp atomic
St().get() %= b;
#pragma omp atomic
@@ -67,7 +70,7 @@ void parallel_atomic_ewc() {
// CHECK: br i1 [[COND]], label %[[OMP_DONE:.+]], label %[[OMP_UPDATE]]
// CHECK: [[OMP_DONE]]
// CHECK: store i32 [[NEW_CALC_VAL]], i32* @a,
- // CHECK: invoke void @_ZN2StD1Ev(%struct.St* [[TEMP_ST_ADDR]])
+ // CHECK: {{invoke|call}} void @_ZN2StD1Ev(%struct.St* [[TEMP_ST_ADDR]])
#pragma omp atomic capture
a = St().get() %= b;
}
diff --git a/test/OpenMP/threadprivate_codegen.cpp b/test/OpenMP/threadprivate_codegen.cpp
index d2cbc154cc83..09f5ed5060ba 100644
--- a/test/OpenMP/threadprivate_codegen.cpp
+++ b/test/OpenMP/threadprivate_codegen.cpp
@@ -275,7 +275,7 @@ S1 arr_x[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
// CHECK: {{.*}}[[ARR_LOOP]]{{.*}}
// CHECK-NEXT: [[ARR_ELEMENTPAST:%.*]] = phi [[S1]]* [ [[ARR_CUR]], {{.*}} ], [ [[ARR_ELEMENT:%.*]], {{.*}} ]
// CHECK-NEXT: [[ARR_ELEMENT:%.*]] = getelementptr inbounds [[S1]], [[S1]]* [[ARR_ELEMENTPAST]], i{{.*}} -1
-// CHECK-NEXT: invoke {{.*}} [[S1_DTOR]]([[S1]]* [[ARR_ELEMENT]])
+// CHECK-NEXT: {{call|invoke}} {{.*}} [[S1_DTOR]]([[S1]]* [[ARR_ELEMENT]])
// CHECK: [[ARR_DONE:%.*]] = icmp eq [[S1]]* [[ARR_ELEMENT]], [[ARR_BEGIN]]
// CHECK-NEXT: br i1 [[ARR_DONE]], label %[[ARR_EXIT:.*]], label %[[ARR_LOOP]]
// CHECK: {{.*}}[[ARR_EXIT]]{{.*}}
diff --git a/test/Sema/diagnose_if.c b/test/Sema/diagnose_if.c
new file mode 100644
index 000000000000..219e393bc0cc
--- /dev/null
+++ b/test/Sema/diagnose_if.c
@@ -0,0 +1,152 @@
+// RUN: %clang_cc1 %s -verify -fno-builtin
+
+#define _diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__)))
+
+void failure() _diagnose_if(); // expected-error{{exactly 3 arguments}}
+void failure() _diagnose_if(0); // expected-error{{exactly 3 arguments}}
+void failure() _diagnose_if(0, ""); // expected-error{{exactly 3 arguments}}
+void failure() _diagnose_if(0, "", "error", 1); // expected-error{{exactly 3 arguments}}
+void failure() _diagnose_if(0, 0, "error"); // expected-error{{requires a string}}
+void failure() _diagnose_if(0, "", "invalid"); // expected-error{{invalid diagnostic type for 'diagnose_if'; use "error" or "warning" instead}}
+void failure() _diagnose_if(0, "", "ERROR"); // expected-error{{invalid diagnostic type}}
+void failure(int a) _diagnose_if(a, "", ""); // expected-error{{invalid diagnostic type}}
+void failure() _diagnose_if(a, "", ""); // expected-error{{undeclared identifier 'a'}}
+
+int globalVar;
+void never_constant() _diagnose_if(globalVar, "", "error"); // expected-error{{'diagnose_if' attribute expression never produces a constant expression}} expected-note{{subexpression not valid}}
+void never_constant() _diagnose_if(globalVar, "", "warning"); // expected-error{{'diagnose_if' attribute expression never produces a constant expression}} expected-note{{subexpression not valid}}
+
+int alwaysok(int q) _diagnose_if(0, "", "error");
+int neverok(int q) _diagnose_if(1, "oh no", "error"); // expected-note 5{{from 'diagnose_if' attribute on 'neverok'}}
+int alwayswarn(int q) _diagnose_if(1, "oh no", "warning"); // expected-note 5{{from 'diagnose_if' attribute}}
+int neverwarn(int q) _diagnose_if(0, "", "warning");
+
+void runConstant() {
+ int m;
+ alwaysok(0);
+ alwaysok(1);
+ alwaysok(m);
+
+ {
+ int (*pok)(int) = alwaysok;
+ pok = &alwaysok;
+ }
+
+ neverok(0); // expected-error{{oh no}}
+ neverok(1); // expected-error{{oh no}}
+ neverok(m); // expected-error{{oh no}}
+ {
+ int (*pok)(int) = neverok; // expected-error{{oh no}}
+ pok = &neverok; // expected-error{{oh no}}
+ }
+
+ alwayswarn(0); // expected-warning{{oh no}}
+ alwayswarn(1); // expected-warning{{oh no}}
+ alwayswarn(m); // expected-warning{{oh no}}
+ {
+ int (*pok)(int) = alwayswarn; // expected-warning{{oh no}}
+ pok = &alwayswarn; // expected-warning{{oh no}}
+ }
+
+ neverwarn(0);
+ neverwarn(1);
+ neverwarn(m);
+ {
+ int (*pok)(int) = neverwarn;
+ pok = &neverwarn;
+ }
+}
+
+int abs(int q) _diagnose_if(q >= 0, "redundant abs call", "error"); //expected-note{{from 'diagnose_if'}}
+void runVariable() {
+ int m;
+ abs(-1);
+ abs(1); // expected-error{{redundant abs call}}
+ abs(m);
+
+ int (*pabs)(int) = abs;
+ pabs = &abs;
+}
+
+#define _overloadable __attribute__((overloadable))
+
+int ovl1(const char *n) _overloadable _diagnose_if(n, "oh no", "error"); // expected-note{{oh no}}
+int ovl1(void *m) _overloadable; // expected-note{{candidate function}}
+
+int ovl2(const char *n) _overloadable _diagnose_if(n, "oh no", "error"); // expected-note{{candidate function}}
+int ovl2(char *m) _overloadable; // expected-note{{candidate function}}
+void overloadsYay() {
+ ovl1((void *)0);
+ ovl1(""); // expected-error{{call to unavailable function}}
+
+ ovl2((void *)0); // expected-error{{ambiguous}}
+}
+
+void errorWarnDiagnose1() _diagnose_if(1, "oh no", "error") // expected-note{{from 'diagnose_if'}}
+ _diagnose_if(1, "nop", "warning");
+void errorWarnDiagnose2() _diagnose_if(1, "oh no", "error") // expected-note{{from 'diagnose_if'}}
+ _diagnose_if(1, "nop", "error");
+void errorWarnDiagnose3() _diagnose_if(1, "nop", "warning")
+ _diagnose_if(1, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
+
+void errorWarnDiagnoseArg1(int a) _diagnose_if(a == 1, "oh no", "error") // expected-note{{from 'diagnose_if'}}
+ _diagnose_if(a == 1, "nop", "warning");
+void errorWarnDiagnoseArg2(int a) _diagnose_if(a == 1, "oh no", "error") // expected-note{{from 'diagnose_if'}}
+ _diagnose_if(a == 1, "nop", "error");
+void errorWarnDiagnoseArg3(int a) _diagnose_if(a == 1, "nop", "warning")
+ _diagnose_if(a == 1, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
+
+void runErrorWarnDiagnose() {
+ errorWarnDiagnose1(); // expected-error{{oh no}}
+ errorWarnDiagnose2(); // expected-error{{oh no}}
+ errorWarnDiagnose3(); // expected-error{{oh no}}
+
+ errorWarnDiagnoseArg1(1); // expected-error{{oh no}}
+ errorWarnDiagnoseArg2(1); // expected-error{{oh no}}
+ errorWarnDiagnoseArg3(1); // expected-error{{oh no}}
+}
+
+void warnWarnDiagnose() _diagnose_if(1, "oh no!", "warning") _diagnose_if(1, "foo", "warning"); // expected-note 2{{from 'diagnose_if'}}
+void runWarnWarnDiagnose() {
+ warnWarnDiagnose(); // expected-warning{{oh no!}} expected-warning{{foo}}
+}
+
+void declsStackErr1(int a) _diagnose_if(a & 1, "decl1", "error"); // expected-note 2{{from 'diagnose_if'}}
+void declsStackErr1(int a) _diagnose_if(a & 2, "decl2", "error"); // expected-note{{from 'diagnose_if'}}
+void declsStackErr2();
+void declsStackErr2() _diagnose_if(1, "complaint", "error"); // expected-note{{from 'diagnose_if'}}
+void declsStackErr3() _diagnose_if(1, "complaint", "error"); // expected-note{{from 'diagnose_if'}}
+void declsStackErr3();
+void runDeclsStackErr() {
+ declsStackErr1(0);
+ declsStackErr1(1); // expected-error{{decl1}}
+ declsStackErr1(2); // expected-error{{decl2}}
+ declsStackErr1(3); // expected-error{{decl1}}
+ declsStackErr2(); // expected-error{{complaint}}
+ declsStackErr3(); // expected-error{{complaint}}
+}
+
+void declsStackWarn1(int a) _diagnose_if(a & 1, "decl1", "warning"); // expected-note 2{{from 'diagnose_if'}}
+void declsStackWarn1(int a) _diagnose_if(a & 2, "decl2", "warning"); // expected-note 2{{from 'diagnose_if'}}
+void declsStackWarn2();
+void declsStackWarn2() _diagnose_if(1, "complaint", "warning"); // expected-note{{from 'diagnose_if'}}
+void declsStackWarn3() _diagnose_if(1, "complaint", "warning"); // expected-note{{from 'diagnose_if'}}
+void declsStackWarn3();
+void runDeclsStackWarn() {
+ declsStackWarn1(0);
+ declsStackWarn1(1); // expected-warning{{decl1}}
+ declsStackWarn1(2); // expected-warning{{decl2}}
+ declsStackWarn1(3); // expected-warning{{decl1}} expected-warning{{decl2}}
+ declsStackWarn2(); // expected-warning{{complaint}}
+ declsStackWarn3(); // expected-warning{{complaint}}
+}
+
+void noMsg(int n) _diagnose_if(n, "", "warning"); // expected-note{{from 'diagnose_if'}}
+void runNoMsg() {
+ noMsg(1); // expected-warning{{<no message provided>}}
+}
+
+void alwaysWarnWithArg(int a) _diagnose_if(1 || a, "alwaysWarn", "warning"); // expected-note{{from 'diagnose_if'}}
+void runAlwaysWarnWithArg(int a) {
+ alwaysWarnWithArg(a); // expected-warning{{alwaysWarn}}
+}
diff --git a/test/SemaCXX/PR10177.cpp b/test/SemaCXX/PR10177.cpp
index 9286e2935167..59630be50885 100644
--- a/test/SemaCXX/PR10177.cpp
+++ b/test/SemaCXX/PR10177.cpp
@@ -24,6 +24,13 @@ void f() {
(void)class_ref<int, int&, U<2>::a>(); // expected-note {{here}}
};
+template<typename T>
+void not_instantiated() {
+ // These cases (arguably) do not require instantiation of U<i>::a.
+ (void)alias_ref<int, int&, U<3>::a>();
+ (void)func_ref<int, int&, U<4>::a>();
+ (void)class_ref<int, int&, U<5>::a>();
+};
template<int N>
void fi() {
@@ -33,7 +40,7 @@ void fi() {
};
int main() {
- f<int>(); // NOTE: Non-dependent name uses are type-checked at template definition time.
+ f<int>(); // expected-note 3{{here}}
fi<10>(); // expected-note 3{{here}}
}
diff --git a/test/SemaCXX/attr-mode-tmpl.cpp b/test/SemaCXX/attr-mode-tmpl.cpp
index 4e1489a8a5bd..d83bb3989050 100644
--- a/test/SemaCXX/attr-mode-tmpl.cpp
+++ b/test/SemaCXX/attr-mode-tmpl.cpp
@@ -45,7 +45,7 @@ void CheckMachineMode() {
// Check attributes on function parameters.
template <class T1, class T2>
-void CheckParameters(T1 __attribute__((mode(SI))) paramSI, // expected-note2{{ignored: substitution failure}}
+void CheckParameters(T1 __attribute__((mode(SI))) paramSI, // expected-note{{ignored: substitution failure}} expected-note-re{{not viable: no known conversion from '{{.*}}' (vector of 4 '{{.*}}' values) to 'EnumType' for 2nd argument}}
T1 __attribute__((mode(V4DI))) paramV4DI, // expected-warning{{deprecated}}
T2 __attribute__((mode(SF))) paramSF,
T2 __attribute__((mode(V4DF))) paramV4DF) { // expected-warning{{deprecated}}
diff --git a/test/SemaCXX/attr-noreturn.cpp b/test/SemaCXX/attr-noreturn.cpp
index a8e71db73702..6edc86c43a7d 100644
--- a/test/SemaCXX/attr-noreturn.cpp
+++ b/test/SemaCXX/attr-noreturn.cpp
@@ -244,11 +244,11 @@ namespace PR15291 {
template <typename T>
void qux(T) {}
- // expected-note@+5 {{candidate function [with T = void (*)(int) __attribute__((noreturn))] not viable: no overload of 'baz' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
- // expected-note@+4 {{candidate function [with T = void (*)(int) __attribute__((noreturn))] not viable: no overload of 'qux' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
- // expected-note@+3 {{candidate function [with T = void (*)(int) __attribute__((noreturn))] not viable: no overload of 'bar' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
- // expected-note@+2 {{candidate function [with T = void (*)(int)] not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
- // expected-note@+1 {{candidate function [with T = void (int)] not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
+ // expected-note@+5 {{candidate function not viable: no overload of 'baz' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+ // expected-note@+4 {{candidate function not viable: no overload of 'qux' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+ // expected-note@+3 {{candidate function not viable: no overload of 'bar' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+ // expected-note@+2 {{candidate function not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
+ // expected-note@+1 {{candidate function not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
template <typename T> void accept_T(T) {}
// expected-note@+1 {{candidate function not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index 884f2f30c42f..066832440c75 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1902,9 +1902,9 @@ namespace ZeroSizeTypes {
namespace BadDefaultInit {
template<int N> struct X { static const int n = N; };
- struct A { // expected-error {{default member initializer for 'k' needed within definition of enclosing class}}
+ struct A {
int k = // expected-note {{default member initializer declared here}}
- X<A().k>::n; // expected-error {{not a constant expression}} expected-note {{implicit default constructor for 'BadDefaultInit::A' first required here}}
+ X<A().k>::n; // expected-error {{default member initializer for 'k' needed within definition of enclosing class}}
};
// FIXME: The "constexpr constructor must initialize all members" diagnostic
diff --git a/test/SemaCXX/cxx1z-constexpr-lambdas.cpp b/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
index 90a07665cbf7..16d5730d3d4c 100644
--- a/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
+++ b/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
@@ -59,4 +59,118 @@ void f(char c) { //expected-note{{declared here}}
}
}
+
+namespace test_conversion_function_for_non_capturing_lambdas {
+
+namespace ns1 {
+auto L = [](int i) { return i; };
+constexpr int (*fpi)(int) = L;
+static_assert(fpi(3) == 3);
+auto GL = [](auto a) { return a; };
+
+constexpr char (*fp2)(char) = GL;
+constexpr double (*fp3)(double) = GL;
+constexpr const char* (*fp4)(const char*) = GL;
+static_assert(fp2('3') == '3');
+static_assert(fp3(3.14) == 3.14);
+constexpr const char *Str = "abc";
+static_assert(fp4(Str) == Str);
+
+auto NCL = [](int i) { static int j; return j; }; //expected-note{{declared here}}
+constexpr int (*fp5)(int) = NCL;
+constexpr int I = //expected-error{{must be initialized by a constant expression}}
+ fp5(5); //expected-note{{non-constexpr function}}
+
+namespace test_dont_always_instantiate_constexpr_templates {
+
+auto explicit_return_type = [](auto x) -> int { return x.get(); };
+decltype(explicit_return_type(0)) c; // OK
+
+auto deduced_return_type = [](auto x) { return x.get(); }; //expected-error{{not a structure or union}}
+decltype(deduced_return_type(0)) d; //expected-note{{requested here}}
+
+
+
+} // end ns test_dont_always_instantiate_constexpr_templates
+} // end ns1
+
+} // end ns test_conversion_function_for_non_capturing_lambdas
+
+namespace test_lambda_is_cce {
+namespace ns1_simple_lambda {
+
+namespace ns0 {
+constexpr int I = [](auto a) { return a; }(10);
+
+static_assert(I == 10);
+static_assert(10 == [](auto a) { return a; }(10));
+static_assert(3.14 == [](auto a) { return a; }(3.14));
+
+} //end ns0
+
+namespace ns1 {
+constexpr auto f(int i) {
+ double d = 3.14;
+ auto L = [=](auto a) {
+ int Isz = sizeof(i);
+ return sizeof(i) + sizeof(a) + sizeof(d);
+ };
+ int I = L("abc") + L(nullptr);
+ return L;
+}
+constexpr auto L = f(3);
+constexpr auto M = L("abc") + L(nullptr);
+
+static_assert(M == sizeof(int) * 2 + sizeof(double) * 2 + sizeof(nullptr) + sizeof(const char*));
+
+} // end ns1
+
+namespace ns2 {
+constexpr auto f(int i) {
+ auto L = [](auto a) { return a + a; };
+ return L;
+}
+constexpr auto L = f(3);
+constexpr int I = L(6);
+static_assert(I == 12);
+} // end ns2
+
+namespace contained_lambdas_call_operator_is_not_constexpr {
+constexpr auto f(int i) {
+ double d = 3.14;
+ auto L = [=](auto a) { //expected-note{{declared here}}
+ int Isz = sizeof(i);
+ asm("hello");
+ return sizeof(i) + sizeof(a) + sizeof(d);
+ };
+ return L;
+}
+
+constexpr auto L = f(3);
+
+constexpr auto M = // expected-error{{must be initialized by}}
+ L("abc"); //expected-note{{non-constexpr function}}
+
+} // end ns contained_lambdas_call_operator_is_not_constexpr
+
+
+
+} // end ns1_simple_lambda
+
+namespace ns1_unimplemented {
+namespace ns1_captures {
+constexpr auto f(int i) {
+ double d = 3.14;
+ auto L = [=](auto a) { //expected-note{{coming soon}}
+ int Isz = i + d;
+ return sizeof(i) + sizeof(a) + sizeof(d);
+ };
+ return L;
+}
+constexpr auto M = f(3); //expected-error{{constant expression}} expected-note{{in call to}}
+} // end ns1_captures
+} // end ns1_unimplemented
+
+} // end ns test_lambda_is_cce
+
#endif // ndef CPP14_AND_EARLIER
diff --git a/test/SemaCXX/diagnose_if.cpp b/test/SemaCXX/diagnose_if.cpp
new file mode 100644
index 000000000000..f97b79d03529
--- /dev/null
+++ b/test/SemaCXX/diagnose_if.cpp
@@ -0,0 +1,460 @@
+// RUN: %clang_cc1 %s -verify -fno-builtin -std=c++14
+
+#define _diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__)))
+
+namespace type_dependent {
+template <typename T>
+void neverok() _diagnose_if(!T(), "oh no", "error") {} // expected-note 4{{from 'diagnose_if'}}
+
+template <typename T>
+void alwaysok() _diagnose_if(T(), "oh no", "error") {}
+
+template <typename T>
+void alwayswarn() _diagnose_if(!T(), "oh no", "warning") {} // expected-note 4{{from 'diagnose_if'}}
+
+template <typename T>
+void neverwarn() _diagnose_if(T(), "oh no", "warning") {}
+
+void runAll() {
+ alwaysok<int>();
+ alwaysok<int>();
+
+ {
+ void (*pok)() = alwaysok<int>;
+ pok = &alwaysok<int>;
+ }
+
+ neverok<int>(); // expected-error{{oh no}}
+ neverok<short>(); // expected-error{{oh no}}
+
+ {
+ void (*pok)() = neverok<int>; // expected-error{{oh no}}
+ }
+ {
+ void (*pok)();
+ pok = &neverok<int>; // expected-error{{oh no}}
+ }
+
+ alwayswarn<int>(); // expected-warning{{oh no}}
+ alwayswarn<short>(); // expected-warning{{oh no}}
+ {
+ void (*pok)() = alwayswarn<int>; // expected-warning{{oh no}}
+ pok = &alwayswarn<int>; // expected-warning{{oh no}}
+ }
+
+ neverwarn<int>();
+ neverwarn<short>();
+ {
+ void (*pok)() = neverwarn<int>;
+ pok = &neverwarn<int>;
+ }
+}
+
+template <typename T>
+void errorIf(T a) _diagnose_if(T() != a, "oh no", "error") {} // expected-note {{candidate disabled: oh no}}
+
+template <typename T>
+void warnIf(T a) _diagnose_if(T() != a, "oh no", "warning") {} // expected-note {{from 'diagnose_if'}}
+
+void runIf() {
+ errorIf(0);
+ errorIf(1); // expected-error{{call to unavailable function}}
+
+ warnIf(0);
+ warnIf(1); // expected-warning{{oh no}}
+}
+}
+
+namespace value_dependent {
+template <int N>
+void neverok() _diagnose_if(N == 0 || N != 0, "oh no", "error") {} // expected-note 4{{from 'diagnose_if'}}
+
+template <int N>
+void alwaysok() _diagnose_if(N == 0 && N != 0, "oh no", "error") {}
+
+template <int N>
+void alwayswarn() _diagnose_if(N == 0 || N != 0, "oh no", "warning") {} // expected-note 4{{from 'diagnose_if'}}
+
+template <int N>
+void neverwarn() _diagnose_if(N == 0 && N != 0, "oh no", "warning") {}
+
+void runAll() {
+ alwaysok<0>();
+ alwaysok<1>();
+
+ {
+ void (*pok)() = alwaysok<0>;
+ pok = &alwaysok<0>;
+ }
+
+ neverok<0>(); // expected-error{{oh no}}
+ neverok<1>(); // expected-error{{oh no}}
+
+ {
+ void (*pok)() = neverok<0>; // expected-error{{oh no}}
+ }
+ {
+ void (*pok)();
+ pok = &neverok<0>; // expected-error{{oh no}}
+ }
+
+ alwayswarn<0>(); // expected-warning{{oh no}}
+ alwayswarn<1>(); // expected-warning{{oh no}}
+ {
+ void (*pok)() = alwayswarn<0>; // expected-warning{{oh no}}
+ pok = &alwayswarn<0>; // expected-warning{{oh no}}
+ }
+
+ neverwarn<0>();
+ neverwarn<1>();
+ {
+ void (*pok)() = neverwarn<0>;
+ pok = &neverwarn<0>;
+ }
+}
+
+template <int N>
+void errorIf(int a) _diagnose_if(N != a, "oh no", "error") {} // expected-note {{candidate disabled: oh no}}
+
+template <int N>
+void warnIf(int a) _diagnose_if(N != a, "oh no", "warning") {} // expected-note {{from 'diagnose_if'}}
+
+void runIf() {
+ errorIf<0>(0);
+ errorIf<0>(1); // expected-error{{call to unavailable function}}
+
+ warnIf<0>(0);
+ warnIf<0>(1); // expected-warning{{oh no}}
+}
+}
+
+namespace no_overload_interaction {
+void foo(int) _diagnose_if(1, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
+void foo(short);
+
+void bar(int);
+void bar(short) _diagnose_if(1, "oh no", "error");
+
+void fooArg(int a) _diagnose_if(a, "oh no", "error"); // expected-note{{candidate disabled: oh no}}
+void fooArg(short); // expected-note{{candidate function}}
+
+void barArg(int);
+void barArg(short a) _diagnose_if(a, "oh no", "error");
+
+void runAll() {
+ foo(1); // expected-error{{oh no}}
+ bar(1);
+
+ fooArg(1); // expected-error{{call to unavailable function}}
+ barArg(1);
+
+ auto p = foo; // expected-error{{incompatible initializer of type '<overloaded function type>'}}
+}
+}
+
+namespace with_default_args {
+void foo(int a = 0) _diagnose_if(a, "oh no", "warning"); // expected-note 1{{from 'diagnose_if'}}
+void bar(int a = 1) _diagnose_if(a, "oh no", "warning"); // expected-note 2{{from 'diagnose_if'}}
+
+void runAll() {
+ foo();
+ foo(0);
+ foo(1); // expected-warning{{oh no}}
+
+ bar(); // expected-warning{{oh no}}
+ bar(0);
+ bar(1); // expected-warning{{oh no}}
+}
+}
+
+namespace naked_mem_expr {
+struct Foo {
+ void foo(int a) _diagnose_if(a, "should warn", "warning"); // expected-note{{from 'diagnose_if'}}
+ void bar(int a) _diagnose_if(a, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
+};
+
+void runFoo() {
+ Foo().foo(0);
+ Foo().foo(1); // expected-warning{{should warn}}
+
+ Foo().bar(0);
+ Foo().bar(1); // expected-error{{oh no}}
+}
+}
+
+namespace class_template {
+template <typename T>
+struct Errors {
+ void foo(int i) _diagnose_if(i, "bad i", "error"); // expected-note{{from 'diagnose_if'}}
+ void bar(int i) _diagnose_if(i != T(), "bad i", "error"); // expected-note{{from 'diagnose_if'}}
+
+ void fooOvl(int i) _diagnose_if(i, "int bad i", "error"); // expected-note 2{{int bad i}}
+ void fooOvl(short i) _diagnose_if(i, "short bad i", "error"); // expected-note 2{{short bad i}}
+
+ void barOvl(int i) _diagnose_if(i != T(), "int bad i", "error"); // expected-note 2{{int bad i}}
+ void barOvl(short i) _diagnose_if(i != T(), "short bad i", "error"); // expected-note 2{{short bad i}}
+};
+
+void runErrors() {
+ Errors<int>().foo(0);
+ Errors<int>().foo(1); // expected-error{{bad i}}
+
+ Errors<int>().bar(0);
+ Errors<int>().bar(1); // expected-error{{bad i}}
+
+ Errors<int>().fooOvl(0);
+ Errors<int>().fooOvl(1); // expected-error{{call to unavailable}}
+ Errors<int>().fooOvl(short(0));
+ Errors<int>().fooOvl(short(1)); // expected-error{{call to unavailable}}
+
+ Errors<int>().barOvl(0);
+ Errors<int>().barOvl(1); // expected-error{{call to unavailable}}
+ Errors<int>().barOvl(short(0));
+ Errors<int>().barOvl(short(1)); // expected-error{{call to unavailable}}
+}
+
+template <typename T>
+struct Warnings {
+ void foo(int i) _diagnose_if(i, "bad i", "warning"); // expected-note{{from 'diagnose_if'}}
+ void bar(int i) _diagnose_if(i != T(), "bad i", "warning"); // expected-note{{from 'diagnose_if'}}
+
+ void fooOvl(int i) _diagnose_if(i, "int bad i", "warning"); // expected-note{{from 'diagnose_if'}}
+ void fooOvl(short i) _diagnose_if(i, "short bad i", "warning"); // expected-note{{from 'diagnose_if'}}
+
+ void barOvl(int i) _diagnose_if(i != T(), "int bad i", "warning"); // expected-note{{from 'diagnose_if'}}
+ void barOvl(short i) _diagnose_if(i != T(), "short bad i", "warning"); // expected-note{{from 'diagnose_if'}}
+};
+
+void runWarnings() {
+ Warnings<int>().foo(0);
+ Warnings<int>().foo(1); // expected-warning{{bad i}}
+
+ Warnings<int>().bar(0);
+ Warnings<int>().bar(1); // expected-warning{{bad i}}
+
+ Warnings<int>().fooOvl(0);
+ Warnings<int>().fooOvl(1); // expected-warning{{int bad i}}
+ Warnings<int>().fooOvl(short(0));
+ Warnings<int>().fooOvl(short(1)); // expected-warning{{short bad i}}
+
+ Warnings<int>().barOvl(0);
+ Warnings<int>().barOvl(1); // expected-warning{{int bad i}}
+ Warnings<int>().barOvl(short(0));
+ Warnings<int>().barOvl(short(1)); // expected-warning{{short bad i}}
+}
+}
+
+namespace template_specialization {
+template <typename T>
+struct Foo {
+ void foo() _diagnose_if(1, "override me", "error"); // expected-note{{from 'diagnose_if'}}
+ void bar(int i) _diagnose_if(i, "bad i", "error"); // expected-note{{from 'diagnose_if'}}
+ void baz(int i);
+};
+
+template <>
+struct Foo<int> {
+ void foo();
+ void bar(int i);
+ void baz(int i) _diagnose_if(i, "bad i", "error"); // expected-note{{from 'diagnose_if'}}
+};
+
+void runAll() {
+ Foo<double>().foo(); // expected-error{{override me}}
+ Foo<int>().foo();
+
+ Foo<double>().bar(1); // expected-error{{bad i}}
+ Foo<int>().bar(1);
+
+ Foo<double>().baz(1);
+ Foo<int>().baz(1); // expected-error{{bad i}}
+}
+}
+
+namespace late_constexpr {
+constexpr int foo();
+constexpr int foo(int a);
+
+void bar() _diagnose_if(foo(), "bad foo", "error"); // expected-note{{from 'diagnose_if'}} expected-note{{not viable: requires 0 arguments}}
+void bar(int a) _diagnose_if(foo(a), "bad foo", "error"); // expected-note{{bad foo}}
+
+void early() {
+ bar();
+ bar(0);
+ bar(1);
+}
+
+constexpr int foo() { return 1; }
+constexpr int foo(int a) { return a; }
+
+void late() {
+ bar(); // expected-error{{bad foo}}
+ bar(0);
+ bar(1); // expected-error{{call to unavailable function}}
+}
+}
+
+namespace late_parsed {
+struct Foo {
+ int i;
+ constexpr Foo(int i): i(i) {}
+ constexpr bool isFooable() const { return i; }
+
+ void go() const _diagnose_if(isFooable(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
+ operator int() const _diagnose_if(isFooable(), "oh no", "error") { return 1; } // expected-note{{oh no}}
+
+ void go2() const _diagnose_if(isFooable(), "oh no", "error") // expected-note{{oh no}}
+ __attribute__((enable_if(true, ""))) {}
+ void go2() const _diagnose_if(isFooable(), "oh no", "error") {} // expected-note{{oh no}}
+
+ constexpr int go3() const _diagnose_if(isFooable(), "oh no", "error")
+ __attribute__((enable_if(true, ""))) {
+ return 1;
+ }
+
+ constexpr int go4() const _diagnose_if(isFooable(), "oh no", "error") {
+ return 1;
+ }
+ constexpr int go4() const _diagnose_if(isFooable(), "oh no", "error")
+ __attribute__((enable_if(true, ""))) {
+ return 1;
+ }
+
+ // We hope to support emitting these errors in the future. For now, though...
+ constexpr int runGo() const {
+ return go3() + go4();
+ }
+};
+
+void go(const Foo &f) _diagnose_if(f.isFooable(), "oh no", "error") {} // expected-note{{oh no}}
+
+void run() {
+ Foo(0).go();
+ Foo(1).go(); // expected-error{{oh no}}
+
+ (void)int(Foo(0));
+ (void)int(Foo(1)); // expected-error{{uses deleted function}}
+
+ Foo(0).go2();
+ Foo(1).go2(); // expected-error{{call to unavailable member function}}
+
+ go(Foo(0));
+ go(Foo(1)); // expected-error{{call to unavailable function}}
+}
+}
+
+namespace member_templates {
+struct Foo {
+ int i;
+ constexpr Foo(int i): i(i) {}
+ constexpr bool bad() const { return i; }
+
+ template <typename T> T getVal() _diagnose_if(bad(), "oh no", "error") { // expected-note{{oh no}}
+ return T();
+ }
+
+ template <typename T>
+ constexpr T getVal2() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{oh no}}
+ return T();
+ }
+
+ template <typename T>
+ constexpr operator T() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{oh no}}
+ return T();
+ }
+
+ // We hope to support emitting these errors in the future.
+ int run() { return getVal<int>() + getVal2<int>() + int(*this); }
+};
+
+void run() {
+ Foo(0).getVal<int>();
+ Foo(1).getVal<int>(); // expected-error{{call to unavailable member function}}
+
+ Foo(0).getVal2<int>();
+ Foo(1).getVal2<int>(); // expected-error{{call to unavailable member function}}
+
+ (void)int(Foo(0));
+ (void)int(Foo(1)); // expected-error{{uses deleted function}}
+}
+}
+
+namespace special_member_operators {
+struct Bar { int j; };
+struct Foo {
+ int i;
+ constexpr Foo(int i): i(i) {}
+ constexpr bool bad() const { return i; }
+ const Bar *operator->() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{oh no}}
+ return nullptr;
+ }
+ void operator()() const _diagnose_if(bad(), "oh no", "error") {} // expected-note{{oh no}}
+};
+
+struct ParenOverload {
+ int i;
+ constexpr ParenOverload(int i): i(i) {}
+ constexpr bool bad() const { return i; }
+ void operator()(double) const _diagnose_if(bad(), "oh no", "error") {} // expected-note 2{{oh no}}
+ void operator()(int) const _diagnose_if(bad(), "oh no", "error") {} // expected-note 2{{oh no}}
+};
+
+struct ParenTemplate {
+ int i;
+ constexpr ParenTemplate(int i): i(i) {}
+ constexpr bool bad() const { return i; }
+ template <typename T>
+ void operator()(T) const _diagnose_if(bad(), "oh no", "error") {} // expected-note 2{{oh no}}
+};
+
+void run() {
+ (void)Foo(0)->j;
+ (void)Foo(1)->j; // expected-error{{selected unavailable operator '->'}}
+
+ Foo(0)();
+ Foo(1)(); // expected-error{{unavailable function call operator}}
+
+ ParenOverload(0)(1);
+ ParenOverload(0)(1.);
+
+ ParenOverload(1)(1); // expected-error{{unavailable function call operator}}
+ ParenOverload(1)(1.); // expected-error{{unavailable function call operator}}
+
+ ParenTemplate(0)(1);
+ ParenTemplate(0)(1.);
+
+ ParenTemplate(1)(1); // expected-error{{unavailable function call operator}}
+ ParenTemplate(1)(1.); // expected-error{{unavailable function call operator}}
+}
+
+void runLambda() {
+ auto L1 = [](int i) _diagnose_if(i, "oh no", "error") {}; // expected-note{{oh no}} expected-note{{conversion candidate}}
+ L1(0);
+ L1(1); // expected-error{{call to unavailable function call}}
+}
+}
+
+namespace ctors {
+struct Foo {
+ int I;
+ constexpr Foo(int I): I(I) {}
+
+ constexpr const Foo &operator=(const Foo &) const // expected-note 2{{disabled: oh no}}
+ _diagnose_if(I, "oh no", "error") {
+ return *this;
+ }
+
+ constexpr const Foo &operator=(const Foo &&) const // expected-note{{disabled: oh no}} expected-note{{no known conversion}}
+ _diagnose_if(I, "oh no", "error") {
+ return *this;
+ }
+};
+
+void run() {
+ constexpr Foo F{0};
+ constexpr Foo F2{1};
+
+ F2 = F; // expected-error{{selected unavailable operator}}
+ F2 = Foo{2}; // expected-error{{selected unavailable operator}}
+}
+}
diff --git a/test/SemaCXX/enable_if.cpp b/test/SemaCXX/enable_if.cpp
index 0f8fc9b2652a..eababc34d370 100644
--- a/test/SemaCXX/enable_if.cpp
+++ b/test/SemaCXX/enable_if.cpp
@@ -464,3 +464,11 @@ void runFoo() {
Foo<double>().bar(1);
}
}
+
+namespace instantiate_constexpr_in_enable_if {
+ template<typename T> struct X {
+ static constexpr bool ok() { return true; }
+ void f() __attribute__((enable_if(ok(), "")));
+ };
+ void g() { X<int>().f(); }
+}
diff --git a/test/SemaCXX/implicit-exception-spec.cpp b/test/SemaCXX/implicit-exception-spec.cpp
index 12871b8ce707..fc86d1810ba5 100644
--- a/test/SemaCXX/implicit-exception-spec.cpp
+++ b/test/SemaCXX/implicit-exception-spec.cpp
@@ -16,34 +16,32 @@ namespace InClassInitializers {
// Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept())
// is false.
bool ThrowSomething() noexcept(false);
- struct ConstExpr { // expected-error {{default member initializer for 'b' needed}}
- bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-note {{declared here}}
- // expected-note@-1 {{implicit default constructor for 'InClassInitializers::ConstExpr' first required here}}
+ struct ConstExpr {
+ bool b = // expected-note {{declared here}}
+ noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{default member initializer for 'b' needed}}
};
// Much more obviously broken: we can't parse the initializer without already
// knowing whether it produces a noexcept expression.
- struct TemplateArg { // expected-error {{default member initializer for 'n' needed}}
- int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-note {{declared here}}
- // expected-note@-1 {{implicit default constructor for 'InClassInitializers::TemplateArg' first required here}}
+ struct TemplateArg {
+ int n = // expected-note {{declared here}}
+ ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{default member initializer for 'n' needed}}
};
// And within a nested class.
- struct Nested { // expected-note {{implicit default constructor for 'InClassInitializers::Nested::Inner' first required here}}
- struct Inner { // expected-error {{default member initializer for 'n' needed}}
+ struct Nested {
+ struct Inner {
int n = // expected-note {{declared here}}
- ExceptionIf<noexcept(Nested())>::f(); // expected-note {{implicit default constructor for 'InClassInitializers::Nested' first required here}}
- } inner;
+ ExceptionIf<noexcept(Nested())>::f();
+ } inner; // expected-error {{default member initializer for 'n' needed}}
};
- struct Nested2 { // expected-error {{implicit default constructor for 'InClassInitializers::Nested2' must explicitly initialize the member 'inner' which does not have a default constructor}}
+ struct Nested2 {
struct Inner;
- int n = Inner().n; // expected-note {{implicit default constructor for 'InClassInitializers::Nested2::Inner' first required here}}
- struct Inner { // expected-error {{initializer for 'n' needed}} expected-note {{declared here}}
- // expected-note@+1 {{declared here}}
- int n = ExceptionIf<noexcept(Nested2())>::f();
- // expected-note@-1 {{implicit default constructor for 'InClassInitializers::Nested2' first required here}}
- } inner; // expected-note {{member is declared here}}
+ int n = Inner().n; // expected-error {{initializer for 'n' needed}}
+ struct Inner {
+ int n = ExceptionIf<noexcept(Nested2())>::f(); // expected-note {{declared here}}
+ } inner;
};
}
diff --git a/test/SemaCXX/libstdcxx_gets_hack.cpp b/test/SemaCXX/libstdcxx_gets_hack.cpp
new file mode 100644
index 000000000000..0d915d01474c
--- /dev/null
+++ b/test/SemaCXX/libstdcxx_gets_hack.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++14 -verify
+
+// This is a test for an egregious hack in Clang that works around
+// an issue with libstdc++'s detection of whether glibc provides a
+// ::gets function. If there is no ::gets, ignore
+// using ::gets;
+// in namespace std.
+//
+// See PR18402 and gcc.gnu.org/PR77795 for more details.
+
+#ifdef BE_THE_HEADER
+
+#pragma GCC system_header
+namespace std {
+ using ::gets;
+ using ::getx; // expected-error {{no member named 'getx'}}
+}
+
+#else
+
+#define BE_THE_HEADER
+#include "libstdcxx_pointer_return_false_hack.cpp"
+
+namespace foo {
+ using ::gets; // expected-error {{no member named 'gets'}}
+}
+
+#endif
diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp
index 105c2e49822f..c296baa5bce7 100644
--- a/test/SemaCXX/member-init.cpp
+++ b/test/SemaCXX/member-init.cpp
@@ -13,10 +13,10 @@ public:
bool b();
int k;
-struct Recurse { // expected-error {{initializer for 'n' needed}}
+struct Recurse {
int &n = // expected-note {{declared here}}
b() ?
- Recurse().n : // expected-note {{implicit default constructor for 'Recurse' first required here}}
+ Recurse().n : // expected-error {{initializer for 'n' needed}}
k;
};
@@ -128,21 +128,19 @@ A::A() {}
namespace template_default_ctor {
struct A {
template <typename T>
- struct B { // expected-error {{initializer for 'm1' needed}}
+ struct B {
int m1 = 0; // expected-note {{declared here}}
};
- // expected-note@+1 {{implicit default constructor for 'template_default_ctor::A::B<int>' first required here}}
- enum { NOE = noexcept(B<int>()) };
+ enum { NOE = noexcept(B<int>()) }; // expected-error {{initializer for 'm1' needed}}
};
}
namespace default_ctor {
struct A {
- struct B { // expected-error {{initializer for 'm1' needed}}
+ struct B {
int m1 = 0; // expected-note {{declared here}}
};
- // expected-note@+1 {{implicit default constructor for 'default_ctor::A::B' first required here}}
- enum { NOE = noexcept(B()) };
+ enum { NOE = noexcept(B()) }; // expected-error {{initializer for 'm1' needed}}
};
}
@@ -150,19 +148,17 @@ namespace member_template {
struct A {
template <typename T>
struct B {
- struct C { // expected-error {{initializer for 'm1' needed}}
+ struct C {
int m1 = 0; // expected-note {{declared here}}
};
template <typename U>
- struct D { // expected-error {{initializer for 'm1' needed}}
+ struct D {
int m1 = 0; // expected-note {{declared here}}
};
};
enum {
- // expected-note@+1 {{implicit default constructor for 'member_template::A::B<int>::C' first required here}}
- NOE1 = noexcept(B<int>::C()),
- // expected-note@+1 {{implicit default constructor for 'member_template::A::B<int>::D<int>' first required here}}
- NOE2 = noexcept(B<int>::D<int>())
+ NOE1 = noexcept(B<int>::C()), // expected-error {{initializer for 'm1' needed}}
+ NOE2 = noexcept(B<int>::D<int>()) // expected-error {{initializer for 'm1' needed}}
};
};
}
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index 3a01bf24b31a..0e3a9ee50bb2 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -338,7 +338,7 @@ namespace PR5756 {
// Tests the exact text used to note the candidates
namespace test1 {
- template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}}
+ template <class T> void foo(T t, unsigned N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}}
void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'char' for 2nd argument}}
void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}}
void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
diff --git a/test/SemaCXX/overload-member-call.cpp b/test/SemaCXX/overload-member-call.cpp
index e0f34d937f6f..6e64b25d6b53 100644
--- a/test/SemaCXX/overload-member-call.cpp
+++ b/test/SemaCXX/overload-member-call.cpp
@@ -70,7 +70,7 @@ void test_X2(X2 *x2p, const X2 *cx2p) {
// Tests the exact text used to note the candidates
namespace test1 {
class A {
- template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}}
+ template <class T> void foo(T t, unsigned N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}}
void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'char' for 2nd argument}}
void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}}
void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
diff --git a/test/SemaCXX/undefined-internal.cpp b/test/SemaCXX/undefined-internal.cpp
index 59e6fdf9af06..32151b71ea17 100644
--- a/test/SemaCXX/undefined-internal.cpp
+++ b/test/SemaCXX/undefined-internal.cpp
@@ -186,10 +186,15 @@ namespace OverloadUse {
namespace {
void f();
void f(int); // expected-warning {{function 'OverloadUse::(anonymous namespace)::f' has internal linkage but is not defined}}
+ void f(int, int); // expected-warning {{function 'OverloadUse::(anonymous namespace)::f' has internal linkage but is not defined}}
+ }
+ template<void x()> void t() { x(); }
+ template<void x(int)> void t(int*) { x(10); }
+ template<void x(int, int)> void t(int*, int*) {}
+ void g(int n) {
+ t<f>(&n); // expected-note {{used here}}
+ t<f>(&n, &n); // expected-note {{used here}}
}
- template<void x()> void t(int*) { x(); }
- template<void x(int)> void t(long*) { x(10); } // expected-note {{used here}}
- void g() { long a; t<f>(&a); }
}
namespace test7 {
diff --git a/test/SemaTemplate/alias-templates.cpp b/test/SemaTemplate/alias-templates.cpp
index bcdc84e19f7e..d70e86817849 100644
--- a/test/SemaTemplate/alias-templates.cpp
+++ b/test/SemaTemplate/alias-templates.cpp
@@ -244,3 +244,13 @@ namespace redecl {
template<typename = void> using A = int;
A<> a; // ok
}
+
+namespace PR31514 {
+ template<typename T, typename> using EnableTupleSize = T;
+
+ template<typename T> struct tuple_size { static const int value = 0; };
+ template<typename T> struct tuple_size<EnableTupleSize<const T, decltype(tuple_size<T>::value)>> {};
+ template<typename T> struct tuple_size<EnableTupleSize<volatile T, decltype(tuple_size<T>::value)>> {};
+
+ tuple_size<const int> t;
+}
diff --git a/test/SemaTemplate/constexpr-instantiate.cpp b/test/SemaTemplate/constexpr-instantiate.cpp
index e8e3e7dd5a08..dfb8a07d3b7d 100644
--- a/test/SemaTemplate/constexpr-instantiate.cpp
+++ b/test/SemaTemplate/constexpr-instantiate.cpp
@@ -77,20 +77,19 @@ namespace Reference {
}
namespace Unevaluated {
- // We follow g++ in treating any reference to a constexpr function template
- // specialization as requiring an instantiation, even if it occurs in an
- // unevaluated context.
+ // We follow the current proposed resolution of core issue 1581: a constexpr
+ // function template specialization requires a definition if:
+ // * it is odr-used, or would be odr-used except that it appears within the
+ // definition of a template, or
+ // * it is used within a braced-init-list, where it may be necessary for
+ // detecting narrowing conversions.
//
- // We go slightly further than g++, and also trigger the implicit definition
- // of a defaulted special member in the same circumstances. This seems scary,
- // since a lot of classes have constexpr special members in C++11, but the
- // only observable impact should be the implicit instantiation of constexpr
- // special member templates (defaulted special members should only be
- // generated if they are well-formed, and non-constexpr special members in a
- // base or member cause the class's special member to not be constexpr).
+ // We apply this both for instantiating constexpr function template
+ // specializations and for implicitly defining defaulted constexpr special
+ // member functions.
//
- // FIXME: None of this is required by the C++ standard. The rules in this
- // area are poorly specified, so this is subject to change.
+ // FIXME: None of this is required by the C++ standard yet. The rules in this
+ // area are subject to change.
namespace NotConstexpr {
template<typename T> struct S {
S() : n(0) {}
@@ -98,16 +97,35 @@ namespace Unevaluated {
int n;
};
struct U : S<int> {};
- decltype(U(U())) u; // ok, don't instantiate S<int>::S() because it wasn't declared constexpr
+ decltype(U(U())) u;
}
namespace Constexpr {
template<typename T> struct S {
constexpr S() : n(0) {}
- constexpr S(const S&) : n(T::error) {} // expected-error {{has no members}}
+ constexpr S(const S&) : n(T::error) {}
int n;
};
- struct U : S<int> {}; // expected-note {{instantiation}}
- decltype(U(U())) u; // expected-note {{here}}
+ struct U : S<int> {};
+ decltype(U(U())) u;
+ }
+ namespace ConstexprList {
+ template<int N> struct S {
+ constexpr S() : n(0) {
+ static_assert(N >= 0, "");
+ }
+ constexpr operator int() const { return 0; }
+ int n;
+ };
+ struct U : S<0> {};
+ // ok, trigger instantiation within a list
+ decltype(char{U()}) t0;
+ decltype(new char{S<1>()}) t1; // expected-warning {{side effects}}
+ decltype((char){S<2>()}) t2;
+ decltype(+(char[1]){{S<3>()}}) t3;
+ // do not trigger instantiation outside a list
+ decltype(char(S<-1>())) u1;
+ decltype(new char(S<-2>())) u2; // expected-warning {{side effects}}
+ decltype((char)(S<-3>())) u3;
}
namespace PR11851_Comment0 {
@@ -190,6 +208,32 @@ namespace Unevaluated {
constexpr duration max = duration();
}
}
+
+ // For variables, we instantiate when they are used in a context in which
+ // evaluation could be required (odr-used, used in a template whose
+ // instantiations would odr-use, or used in list initialization), if they
+ // can be used as a constant (const integral or constexpr).
+ namespace Variables {
+ template<int N> struct A {
+ static const int k;
+ static int n;
+ };
+ template<const int *N> struct B {};
+ template<int N> constexpr int A<N>::k = *(int[N]){N}; // expected-error 1+{{negative}}
+ template<int N> int A<N>::n = *(int[N]){0};
+
+ template <typename> void f() {
+ (void)A<-1>::n; // ok
+ (void)A<-1>::k; // expected-note {{instantiation of }}
+ B<&A<-2>::n> b1; // ok
+ B<&A<-2>::k> b2; // expected-note {{instantiation of }}
+ };
+
+ decltype(A<-3>::k) d1 = 0; // ok
+ decltype(char{A<-4>::k}) d2 = 0; // expected-note {{instantiation of }} expected-error {{narrow}} expected-note {{cast}}
+ decltype(char{A<1>::k}) d3 = 0; // ok
+ decltype(char{A<1 + (unsigned char)-1>::k}) d4 = 0; // expected-error {{narrow}} expected-note {{cast}}
+ }
}
namespace NoInstantiationWhenSelectingOverload {
@@ -201,10 +245,17 @@ namespace NoInstantiationWhenSelectingOverload {
int n;
};
- int f(S);
- int f(int);
+ constexpr int f(S) { return 0; }
+ constexpr int f(int) { return 0; }
void g() { f(0); }
- void h() { (void)sizeof(f(0)); }
- void i() { (void)sizeof(f("oops")); } // expected-note {{instantiation of}}
+ void h() { (void)sizeof(char{f(0)}); }
+ void i() { (void)sizeof(char{f("oops")}); } // expected-note {{instantiation of}}
+}
+
+namespace PR20090 {
+ template <typename T> constexpr T fact(T n) {
+ return n == 0 ? 1 : [=] { return n * fact(n - 1); }();
+ }
+ static_assert(fact(0) == 1, "");
}
diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp
index 2275a8b3b7ad..0c0e7d599ccb 100644
--- a/test/SemaTemplate/deduction.cpp
+++ b/test/SemaTemplate/deduction.cpp
@@ -342,7 +342,7 @@ namespace deduction_substitution_failure {
template<typename T, typename U> struct A {};
template<typename T> struct A<T, typename Fail<T>::error> {}; // expected-note {{instantiation of}}
- A<int, int> ai; // expected-note {{during template argument deduction for class template partial specialization 'A<T, typename Fail<T>::error>' [with T = int]}}
+ A<int, int> ai; // expected-note {{during template argument deduction for class template partial specialization 'A<T, typename Fail<T>::error>' [with T = int]}} expected-note {{in instantiation of template class 'deduction_substitution_failure::A<int, int>'}}
template<typename T, typename U> int B; // expected-warning 0-1 {{extension}}
template<typename T> int B<T, typename Fail<T>::error> {}; // expected-note {{instantiation of}}
@@ -350,17 +350,39 @@ namespace deduction_substitution_failure {
}
namespace deduction_after_explicit_pack {
- template<typename ...T, typename U> int *f(T ...t, int &r, U *u) { // expected-note {{couldn't infer template argument 'U'}}
+ template<typename ...T, typename U> int *f(T ...t, int &r, U *u) {
return u;
}
template<typename U, typename ...T> int *g(T ...t, int &r, U *u) {
return u;
}
void h(float a, double b, int c) {
- // FIXME: Under DR1388, this appears to be valid.
- f<float&, double&>(a, b, c, &c); // expected-error {{no matching}}
+ f<float&, double&>(a, b, c, &c); // ok
g<int, float&, double&>(a, b, c, &c); // ok
}
+
+ template<class... ExtraArgs>
+ int test(ExtraArgs..., unsigned vla_size, const char *input);
+ int n = test(0, "");
+
+ template <typename... T> void i(T..., int, T..., ...); // expected-note 5{{deduced conflicting}}
+ void j() {
+ i(0);
+ i(0, 1); // expected-error {{no match}}
+ i(0, 1, 2); // expected-error {{no match}}
+ i<>(0);
+ i<>(0, 1); // expected-error {{no match}}
+ i<>(0, 1, 2); // expected-error {{no match}}
+ i<int, int>(0, 1, 2, 3, 4);
+ i<int, int>(0, 1, 2, 3, 4, 5); // expected-error {{no match}}
+ }
+
+ // GCC alarmingly accepts this by deducing T={int} by matching the second
+ // parameter against the first argument, then passing the first argument
+ // through the first parameter.
+ template<typename... T> struct X { X(int); operator int(); };
+ template<typename... T> void p(T..., X<T...>, ...); // expected-note {{deduced conflicting}}
+ void q() { p(X<int>(0), 0); } // expected-error {{no match}}
}
namespace overload_vs_pack {
diff --git a/test/SemaTemplate/default-arguments-cxx0x.cpp b/test/SemaTemplate/default-arguments-cxx0x.cpp
index c52899a8e6d1..d9fa2b4a825e 100644
--- a/test/SemaTemplate/default-arguments-cxx0x.cpp
+++ b/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -50,6 +50,8 @@ namespace PR16975 {
bar(T);
};
+ bar<> foo{0};
+
struct baz : public bar<> {
using bar::bar;
};
diff --git a/test/SemaTemplate/instantiate-init.cpp b/test/SemaTemplate/instantiate-init.cpp
index e9be60d16c1f..244e94f6d605 100644
--- a/test/SemaTemplate/instantiate-init.cpp
+++ b/test/SemaTemplate/instantiate-init.cpp
@@ -115,9 +115,8 @@ namespace PR13064 {
struct A { explicit A(int); }; // expected-note{{here}}
template<typename T> struct B { T a { 0 }; };
B<A> b;
- // expected-note@+1 {{in instantiation of default member initializer}}
template<typename T> struct C { T a = { 0 }; }; // expected-error{{explicit}}
- C<A> c; // expected-note{{here}}
+ C<A> c; // expected-note {{in instantiation of default member initializer}}
}
namespace PR16903 {
diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp
index 93f11b5657d0..27a0a03f84f4 100644
--- a/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/test/SemaTemplate/temp_arg_nontype.cpp
@@ -173,12 +173,16 @@ namespace pr6249 {
}
namespace PR6723 {
- template<unsigned char C> void f(int (&a)[C]); // expected-note {{candidate template ignored}} \
- // expected-note{{substitution failure [with C = '\x00']}}
+ template<unsigned char C> void f(int (&a)[C]); // expected-note 3{{candidate template ignored: substitution failure [with C = '\x00']}}
+ // expected-note@-1 {{not viable: no known conversion from 'int [512]' to 'int (&)[0]'}}
void g() {
int arr512[512];
f(arr512); // expected-error{{no matching function for call}}
f<512>(arr512); // expected-error{{no matching function for call}}
+
+ int arr0[0];
+ f(arr0); // expected-error{{no matching function for call}}
+ f<0>(arr0); // expected-error{{no matching function for call}}
}
}
diff --git a/tools/c-index-test/core_main.cpp b/tools/c-index-test/core_main.cpp
index 8976d9134916..0ab24fb6ccb9 100644
--- a/tools/c-index-test/core_main.cpp
+++ b/tools/c-index-test/core_main.cpp
@@ -166,6 +166,8 @@ static bool printSourceSymbols(ArrayRef<const char *> Args) {
static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS) {
OS << getSymbolKindString(SymInfo.Kind);
+ if (SymInfo.SubKind != SymbolSubKind::None)
+ OS << '/' << getSymbolSubKindString(SymInfo.SubKind);
if (SymInfo.Properties) {
OS << '(';
printSymbolProperties(SymInfo.Properties, OS);
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 49bde947f4c6..f6e26fa11f41 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -72,7 +72,7 @@ endforeach()
# Configure plist creation for OS X.
set (TOOL_INFO_PLIST "Info.plist" CACHE STRING "Plist name")
-if (APPLE)
+if (APPLE)
if (CLANG_VENDOR)
set(TOOL_INFO_NAME "${CLANG_VENDOR} clang")
else()
@@ -82,20 +82,19 @@ if (APPLE)
set(TOOL_INFO_UTI "${CLANG_VENDOR_UTI}")
set(TOOL_INFO_VERSION "${CLANG_VERSION}")
set(TOOL_INFO_BUILD_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
-
+
set(TOOL_INFO_PLIST_OUT "${CMAKE_CURRENT_BINARY_DIR}/${TOOL_INFO_PLIST}")
target_link_libraries(clang
"-Wl,-sectcreate,__TEXT,__info_plist,${TOOL_INFO_PLIST_OUT}")
configure_file("${TOOL_INFO_PLIST}.in" "${TOOL_INFO_PLIST_OUT}" @ONLY)
-
+
set(TOOL_INFO_UTI)
set(TOOL_INFO_NAME)
set(TOOL_INFO_VERSION)
set(TOOL_INFO_BUILD_VERSION)
endif()
-# the linker -order_file flag is only supported by ld64
-if(LD64_EXECUTABLE AND CLANG_ORDER_FILE)
+if(CLANG_ORDER_FILE AND (LD64_EXECUTABLE OR GOLD_EXECUTABLE))
include(CMakePushCheckState)
function(check_linker_flag flag out_var)
@@ -105,9 +104,14 @@ if(LD64_EXECUTABLE AND CLANG_ORDER_FILE)
cmake_pop_check_state()
endfunction()
+ if (LD64_EXECUTABLE)
+ set(LINKER_ORDER_FILE_OPTION "-Wl,-order_file,${CLANG_ORDER_FILE}")
+ elseif (GOLD_EXECUTABLE)
+ set(LINKER_ORDER_FILE_OPTION "-Wl,--section-ordering-file,${CLANG_ORDER_FILE}")
+ endif()
+
# This is a test to ensure the actual order file works with the linker.
- check_linker_flag("-Wl,-order_file,${CLANG_ORDER_FILE}"
- LINKER_ORDER_FILE_WORKS)
+ check_linker_flag(${LINKER_ORDER_FILE_OPTION} LINKER_ORDER_FILE_WORKS)
# Passing an empty order file disables some linker layout optimizations.
# To work around this and enable workflows for re-linking when the order file
@@ -117,7 +121,7 @@ if(LD64_EXECUTABLE AND CLANG_ORDER_FILE)
if("${ORDER_FILE}" STREQUAL "\n")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CLANG_ORDER_FILE})
elseif(LINKER_ORDER_FILE_WORKS)
- target_link_libraries(clang "-Wl,-order_file,${CLANG_ORDER_FILE}")
+ target_link_libraries(clang ${LINKER_ORDER_FILE_OPTION})
set_target_properties(clang PROPERTIES LINK_DEPENDS ${CLANG_ORDER_FILE})
endif()
endif()
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 6f9df680eef5..629e85803d64 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -5780,6 +5780,10 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyGoogleFormat("MACRO Constructor(const int& i) : a(a), b(b) {}");
verifyFormat("void f() { f(a, c * d); }");
verifyFormat("void f() { f(new a(), c * d); }");
+ verifyFormat("void f(const MyOverride &override);");
+ verifyFormat("void f(const MyFinal &final);");
+ verifyIndependentOfContext("bool a = f() && override.f();");
+ verifyIndependentOfContext("bool a = f() && final.f();");
verifyIndependentOfContext("InvalidRegions[*R] = 0;");
diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp
index 59f4a4f6dcfe..230717fe47cc 100644
--- a/unittests/Format/FormatTestJS.cpp
+++ b/unittests/Format/FormatTestJS.cpp
@@ -858,6 +858,26 @@ TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
"return 1",
"a = null\n"
" return 1");
+ verifyFormat(
+ "x = {\n"
+ " a: 1\n"
+ "}\n"
+ "class Y {}",
+ " x = {a : 1}\n"
+ " class Y { }");
+}
+
+TEST_F(FormatTestJS, ImportExportASI) {
+ verifyFormat(
+ "import {x} from 'y'\n"
+ "export function z() {}",
+ "import {x} from 'y'\n"
+ " export function z() {}");
+ verifyFormat(
+ "export {x}\n"
+ "class Y {}",
+ " export {x}\n"
+ " class Y {\n}");
}
TEST_F(FormatTestJS, ClosureStyleCasts) {
diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html
index ee8ce025eb47..e7d2e5f87c9c 100644
--- a/www/cxx_dr_status.html
+++ b/www/cxx_dr_status.html
@@ -28,7 +28,7 @@
<!--*************************************************************************-->
<h1>C++ Defect Report Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2017-01-02 12:15:42 +0100 (Mon, 02 Jan 2017) $</p>
+<p>Last updated: $Date: 2017-01-09 09:01:21 +0100 (Mon, 09 Jan 2017) $</p>
<h2 id="cxxdr">C++ defect report implementation status</h2>
@@ -8143,7 +8143,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1388">1388</a></td>
<td>CD3</td>
<td>Missing non-deduced context following a function parameter pack</td>
- <td class="none" align="center">Unknown</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr id="1389">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1389">1389</a></td>
@@ -8161,7 +8161,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1391">1391</a></td>
<td>DRWP</td>
<td>Conversions to parameter types with non-deduced template arguments</td>
- <td class="none" align="center">Unknown</td>
+ <td class="partial" align="center">Partial</td>
</tr>
<tr id="1392">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1392">1392</a></td>
@@ -8209,7 +8209,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1399">1399</a></td>
<td>CD3</td>
<td>Deduction with multiple function parameter packs</td>
- <td class="none" align="center">Unknown</td>
+ <td class="svn" align="center">Duplicate of <a href="#1388">1388</a></td>
</tr>
<tr id="1400">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1400">1400</a></td>