Vendor import of clang trunk r291476:

https://llvm.org/svn/llvm-project/cfe/trunk@291476
This commit is contained in:
dim 2017-01-09 21:23:21 +00:00
parent ffb9ad6832
commit 0778366e3c
118 changed files with 4188 additions and 836 deletions

View File

@ -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

View File

@ -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.

View File

@ -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>;

View File

@ -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 = [{

View File

@ -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<

View File

@ -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

View File

@ -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>;

View File

@ -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")

View File

@ -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">,

View File

@ -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.

View File

@ -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 {

View File

@ -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,

View File

@ -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>());

View File

@ -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 Add a new candidate with NumConversions conversion sequence slots
/// to the overload set.
OverloadCandidate &addCandidate(unsigned NumConversions = 0) {
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);
}
/// \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 (&C.Conversions[i]) ImplicitConversionSequence();
for (unsigned I = 0; I != NumConversions; ++I)
new (&Conversions[I]) ImplicitConversionSequence();
C.NumConversions = NumConversions;
return ConversionSequenceList(Conversions, NumConversions);
}
/// \brief Add a new candidate with NumConversions conversion sequence slots
/// to the overload set.
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();
C.Conversions = Conversions.empty()
? allocateConversionSequences(NumConversions)
: Conversions;
return C;
}

View File

@ -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();

View File

@ -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.

View File

@ -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;
}

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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");

View File

@ -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;

View File

@ -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:

View File

@ -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:

View File

@ -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) &&

View File

@ -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();

View File

@ -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(

View File

@ -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) {

View File

@ -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";

View File

@ -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;

View File

@ -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()));

View File

@ -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) {

View File

@ -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 =

View File

@ -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;

View File

@ -5395,13 +5395,31 @@ 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(),
@ -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();
}

View File

@ -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.)
return false;
case Sema::DiscardedStatement:
// These are technically a potentially evaluated but they have the effect
// of suppressing use marking.
// Expressions in this context are never evaluated.
return false;
case Sema::UnevaluatedList:
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.
// 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.
// 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:
return false;
case Sema::ConstantEvaluated:
case Sema::PotentiallyEvaluated:
return true;
case Sema::PotentiallyEvaluatedIfUsed:
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.

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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,

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -39,6 +39,7 @@ add_clang_library(clangStaticAnalyzerCheckers
GenericTaintChecker.cpp
GTestChecker.cpp
IdenticalExprChecker.cpp
IteratorPastEndChecker.cpp
IvarInvalidationChecker.cpp
LLVMConventionsChecker.cpp
LocalizationChecker.cpp

View File

@ -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>();
}

View File

@ -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;
}

View File

@ -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 { };

View File

@ -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
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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}}
}

View File

@ -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}}
}
}

View File

@ -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
}

View File

@ -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'}}
}

View File

@ -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
}

View File

@ -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}}

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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"

View File

@ -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"

View File

@ -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) {}

View File

@ -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 (...) {

View File

@ -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 }

View File

@ -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;

View File

@ -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"

View File

@ -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

View File

@ -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 \

View File

@ -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:[^"]+]]"

View File

@ -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:[^"]+]]"

View File

@ -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

View File

@ -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
//

View File

@ -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
//

View File

@ -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"

View File

@ -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"

View File

@ -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
//

View File

@ -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

View File

@ -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)?}}"

View File

@ -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"

View File

@ -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

View File

@ -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 {

View File

@ -0,0 +1 @@
// in pch

View File

@ -0,0 +1 @@
#include "D.h"

View File

@ -0,0 +1 @@
//empty

View File

@ -0,0 +1 @@
//empty

View File

@ -0,0 +1,9 @@
module CloudKit {
header "C.h"
export *
}
module Contacts {
header "D.h"
export *
}

View File

@ -0,0 +1 @@
#include "A.h"

View File

@ -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"

View File

@ -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;
}

View File

@ -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]]{{.*}}

152
test/Sema/diagnose_if.c Normal file
View File

@ -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}}
}

View File

@ -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}}
}

View File

@ -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}}

View File

@ -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}}

View File

@ -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

View File

@ -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

View File

@ -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}}
}
}

Some files were not shown because too many files have changed in this diff Show More