diff options
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> |