Vendor import of clang trunk r305575:
https://llvm.org/svn/llvm-project/cfe/trunk@305575
This commit is contained in:
parent
1b08b196ac
commit
325377b573
@ -521,12 +521,12 @@ the configuration (without a prefix: ``Auto``).
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
class foo {};
|
||||
|
||||
false:
|
||||
class foo
|
||||
{};
|
||||
|
||||
false:
|
||||
class foo {};
|
||||
|
||||
* ``bool AfterControlStatement`` Wrap control statements (``if``/``for``/``while``/``switch``/..).
|
||||
|
||||
.. code-block:: c++
|
||||
@ -603,12 +603,12 @@ the configuration (without a prefix: ``Auto``).
|
||||
struct foo
|
||||
{
|
||||
int x;
|
||||
}
|
||||
};
|
||||
|
||||
false:
|
||||
struct foo {
|
||||
int x;
|
||||
}
|
||||
};
|
||||
|
||||
* ``bool AfterUnion`` Wrap union definitions.
|
||||
|
||||
|
@ -187,6 +187,31 @@ Static Analyzer
|
||||
|
||||
...
|
||||
|
||||
Undefined Behavior Sanitizer (UBSan)
|
||||
------------------------------------
|
||||
|
||||
- The Undefined Behavior Sanitizer has a new check for pointer overflow. This
|
||||
check is on by default. The flag to control this functionality is
|
||||
-fsanitize=pointer-overflow.
|
||||
|
||||
Pointer overflow is an indicator of undefined behavior: when a pointer
|
||||
indexing expression wraps around the address space, or produces other
|
||||
unexpected results, its result may not point to a valid object.
|
||||
|
||||
- UBSan has several new checks which detect violations of nullability
|
||||
annotations. These checks are off by default. The flag to control this group
|
||||
of checks is -fsanitize=nullability. The checks can be individially enabled
|
||||
by -fsanitize=nullability-arg (which checks calls),
|
||||
-fsanitize=nullability-assign (which checks assignments), and
|
||||
-fsanitize=nullability-return (which checks return statements).
|
||||
|
||||
- UBSan can now detect invalid loads from bitfields and from ObjC BOOLs.
|
||||
|
||||
- UBSan can now avoid emitting unnecessary type checks in C++ class methods and
|
||||
in several other cases where the result is known at compile-time. UBSan can
|
||||
also avoid emitting unnecessary overflow checks in arithmetic expressions
|
||||
with promoted integer operands.
|
||||
|
||||
Core Analysis Improvements
|
||||
==========================
|
||||
|
||||
|
@ -148,6 +148,12 @@ You can also use the following check groups:
|
||||
nullability does not have undefined behavior, it is often unintentional,
|
||||
so UBSan offers to catch it.
|
||||
|
||||
Volatile
|
||||
--------
|
||||
|
||||
The ``null``, ``alignment``, ``object-size``, and ``vptr`` checks do not apply
|
||||
to pointers to types with the ``volatile`` qualifier.
|
||||
|
||||
Stack traces and report symbolization
|
||||
=====================================
|
||||
If you want UBSan to print symbolized stack trace for each error report, you
|
||||
|
@ -28,7 +28,7 @@
|
||||
namespace clang {
|
||||
template <size_t SizeOfStr, typename FieldType>
|
||||
class StringSizerHelper {
|
||||
char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1];
|
||||
static_assert(SizeOfStr <= FieldType(~0U), "Field too small!");
|
||||
public:
|
||||
enum { Size = SizeOfStr };
|
||||
};
|
||||
|
@ -51,10 +51,10 @@ BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vrfip, "V4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_vcfsx, "V4fV4ii", "")
|
||||
BUILTIN(__builtin_altivec_vcfux, "V4fV4ii", "")
|
||||
BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fi", "")
|
||||
BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fi", "")
|
||||
BUILTIN(__builtin_altivec_vcfsx, "V4fV4iIi", "")
|
||||
BUILTIN(__builtin_altivec_vcfux, "V4fV4iIi", "")
|
||||
BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fIi", "")
|
||||
BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fIi", "")
|
||||
|
||||
BUILTIN(__builtin_altivec_dss, "vUi", "")
|
||||
BUILTIN(__builtin_altivec_dssall, "v", "")
|
||||
|
@ -121,10 +121,12 @@ def err_module_odr_violation_mismatch_decl : Error<
|
||||
"%q0 has different definitions in different modules; first difference is "
|
||||
"%select{definition in module '%2'|defined here}1 found "
|
||||
"%select{end of class|public access specifier|private access specifier|"
|
||||
"protected access specifier|static assert|field|method}3">;
|
||||
"protected access specifier|static assert|field|method|type alias|typedef|"
|
||||
"data member}3">;
|
||||
def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found "
|
||||
"%select{end of class|public access specifier|private access specifier|"
|
||||
"protected access specifier|static assert|field|method}1">;
|
||||
"protected access specifier|static assert|field|method|type alias|typedef|"
|
||||
"data member}1">;
|
||||
|
||||
def err_module_odr_violation_mismatch_decl_diff : Error<
|
||||
"%q0 has different definitions in different modules; first difference is "
|
||||
@ -149,7 +151,17 @@ def err_module_odr_violation_mismatch_decl_diff : Error<
|
||||
"method %4 is %select{not inline|inline}5|"
|
||||
"method %4 that has %5 parameter%s5|"
|
||||
"method %4 with %ordinal5 parameter of type %6%select{| decayed from %8}7|"
|
||||
"method %4 with %ordinal5 parameter named %6}3">;
|
||||
"method %4 with %ordinal5 parameter named %6|"
|
||||
"method %4 with %ordinal5 parameter with%select{out|}6 a default argument|"
|
||||
"method %4 with %ordinal5 parameter with a default argument|"
|
||||
"%select{typedef|type alias}4 name %5|"
|
||||
"%select{typedef|type alias}4 %5 with underlying type %6|"
|
||||
"data member with name %4|"
|
||||
"data member %4 with type %5|"
|
||||
"data member %4 with%select{out|}5 an initializer|"
|
||||
"data member %4 with an initializer|"
|
||||
"data member %4 %select{is constexpr|is not constexpr}5|"
|
||||
"}3">;
|
||||
|
||||
def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
|
||||
"%select{"
|
||||
@ -172,15 +184,27 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
|
||||
"method %2 is %select{not inline|inline}3|"
|
||||
"method %2 that has %3 parameter%s3|"
|
||||
"method %2 with %ordinal3 parameter of type %4%select{| decayed from %6}5|"
|
||||
"method %2 with %ordinal3 parameter named %4}1">;
|
||||
"method %2 with %ordinal3 parameter named %4|"
|
||||
"method %2 with %ordinal3 parameter with%select{out|}4 a default argument|"
|
||||
"method %2 with %ordinal3 parameter with a different default argument|"
|
||||
"%select{typedef|type alias}2 name %3|"
|
||||
"%select{typedef|type alias}2 %3 with different underlying type %4|"
|
||||
"data member with name %2|"
|
||||
"data member %2 with different type %3|"
|
||||
"data member %2 with%select{out|}3 an initializer|"
|
||||
"data member %2 with a different initializer|"
|
||||
"data member %2 %select{is constexpr|is not constexpr}3|"
|
||||
"}1">;
|
||||
|
||||
def err_module_odr_violation_mismatch_decl_unknown : Error<
|
||||
"%q0 %select{with definition in module '%2'|defined here}1 has different "
|
||||
"definitions in different modules; first difference is this "
|
||||
"%select{||||static assert|field|method|unexpected decl}3">;
|
||||
"%select{||||static assert|field|method|type alias|typedef|data member|"
|
||||
"unexpected decl}3">;
|
||||
def note_module_odr_violation_mismatch_decl_unknown : Note<
|
||||
"but in '%0' found "
|
||||
"%select{||||different static assert|different field|different method|"
|
||||
"different type alias|different typedef|different data member|"
|
||||
"another unexpected decl}1">;
|
||||
|
||||
def warn_duplicate_module_file_extension : Warning<
|
||||
|
@ -688,6 +688,18 @@ struct FormatStyle {
|
||||
bool BeforeElse;
|
||||
/// \brief Indent the wrapped braces themselves.
|
||||
bool IndentBraces;
|
||||
/// \brief If ``false``, empty function body can be put on a single line.
|
||||
/// This option is used only if the opening brace of the function has
|
||||
/// already been wrapped, i.e. the `AfterFunction` brace wrapping mode is
|
||||
/// set, and the function could/should not be put on a single line (as per
|
||||
/// `AllowShortFunctionsOnASingleLine` and constructor formatting options).
|
||||
/// \code
|
||||
/// int f() vs. inf f()
|
||||
/// {} {
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
bool SplitEmptyFunctionBody;
|
||||
};
|
||||
|
||||
/// \brief Control of individual brace wrapping cases.
|
||||
@ -779,6 +791,29 @@ struct FormatStyle {
|
||||
/// \endcode
|
||||
bool BreakBeforeInheritanceComma;
|
||||
|
||||
/// \brief If ``true``, consecutive namespace declarations will be on the same
|
||||
/// line. If ``false``, each namespace is declared on a new line.
|
||||
/// \code
|
||||
/// true:
|
||||
/// namespace Foo { namespace Bar {
|
||||
/// }}
|
||||
///
|
||||
/// false:
|
||||
/// namespace Foo {
|
||||
/// namespace Bar {
|
||||
/// }
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// If it does not fit on a single line, the overflowing namespaces get
|
||||
/// wrapped:
|
||||
/// \code
|
||||
/// namespace Foo { namespace Bar {
|
||||
/// namespace Extra {
|
||||
/// }}}
|
||||
/// \endcode
|
||||
bool CompactNamespaces;
|
||||
|
||||
/// \brief If the constructor initializers don't fit on a line, put each
|
||||
/// initializer on its own line.
|
||||
/// \code
|
||||
@ -1410,6 +1445,7 @@ struct FormatStyle {
|
||||
BreakBeforeBraces == R.BreakBeforeBraces &&
|
||||
BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
|
||||
BreakConstructorInitializers == R.BreakConstructorInitializers &&
|
||||
CompactNamespaces == R.CompactNamespaces &&
|
||||
BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations &&
|
||||
BreakStringLiterals == R.BreakStringLiterals &&
|
||||
ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas &&
|
||||
|
@ -317,8 +317,8 @@ public:
|
||||
/// \brief Auxiliary triple for CUDA compilation.
|
||||
std::string AuxTriple;
|
||||
|
||||
/// \brief If non-empty, search the pch input file as it was a header
|
||||
// included by this file.
|
||||
/// \brief If non-empty, search the pch input file as if it was a header
|
||||
/// included by this file.
|
||||
std::string FindPchSource;
|
||||
|
||||
/// Filename to write statistics to.
|
||||
|
@ -53,9 +53,12 @@ class MacroArgs {
|
||||
/// Preprocessor owns which we use to avoid thrashing malloc/free.
|
||||
MacroArgs *ArgCache;
|
||||
|
||||
MacroArgs(unsigned NumToks, bool varargsElided)
|
||||
: NumUnexpArgTokens(NumToks), VarargsElided(varargsElided),
|
||||
ArgCache(nullptr) {}
|
||||
/// MacroArgs - The number of arguments the invoked macro expects.
|
||||
unsigned NumMacroArgs;
|
||||
|
||||
MacroArgs(unsigned NumToks, bool varargsElided, unsigned MacroArgs)
|
||||
: NumUnexpArgTokens(NumToks), VarargsElided(varargsElided),
|
||||
ArgCache(nullptr), NumMacroArgs(MacroArgs) {}
|
||||
~MacroArgs() = default;
|
||||
|
||||
public:
|
||||
@ -94,10 +97,9 @@ public:
|
||||
SourceLocation ExpansionLocStart,
|
||||
SourceLocation ExpansionLocEnd);
|
||||
|
||||
/// getNumArguments - Return the number of arguments passed into this macro
|
||||
/// invocation.
|
||||
unsigned getNumArguments() const { return NumUnexpArgTokens; }
|
||||
|
||||
/// getNumMacroArguments - Return the number of arguments the invoked macro
|
||||
/// expects.
|
||||
unsigned getNumMacroArguments() const { return NumMacroArgs; }
|
||||
|
||||
/// isVarargsElidedUse - Return true if this is a C99 style varargs macro
|
||||
/// invocation and there was no argument specified for the "..." argument. If
|
||||
|
@ -8364,6 +8364,8 @@ public:
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ Coroutines TS
|
||||
//
|
||||
bool ActOnCoroutineBodyStart(Scope *S, SourceLocation KwLoc,
|
||||
StringRef Keyword);
|
||||
ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E);
|
||||
ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E);
|
||||
StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E);
|
||||
|
@ -3565,7 +3565,7 @@ QualType ASTContext::getSubstTemplateTypeParmPackType(
|
||||
= new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon,
|
||||
ArgPack);
|
||||
Types.push_back(SubstParm);
|
||||
SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
|
||||
SubstTemplateTypeParmPackTypes.InsertNode(SubstParm, InsertPos);
|
||||
return QualType(SubstParm, 0);
|
||||
}
|
||||
|
||||
@ -8547,6 +8547,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
|
||||
HowLong = 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
|
||||
case Expr::ArrayInitIndexExprClass:
|
||||
case Expr::NoInitExprClass:
|
||||
case Expr::DesignatedInitUpdateExprClass:
|
||||
case Expr::CoyieldExprClass:
|
||||
return Cl::CL_PRValue;
|
||||
|
||||
// Next come the complicated cases.
|
||||
@ -414,7 +413,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
|
||||
return ClassifyInternal(Ctx, cast<InitListExpr>(E)->getInit(0));
|
||||
|
||||
case Expr::CoawaitExprClass:
|
||||
return ClassifyInternal(Ctx, cast<CoawaitExpr>(E)->getResumeExpr());
|
||||
case Expr::CoyieldExprClass:
|
||||
return ClassifyInternal(Ctx, cast<CoroutineSuspendExpr>(E)->getResumeExpr());
|
||||
}
|
||||
|
||||
llvm_unreachable("unhandled expression kind in classification");
|
||||
|
@ -4588,7 +4588,7 @@ public:
|
||||
}
|
||||
|
||||
bool handleCallExpr(const CallExpr *E, APValue &Result,
|
||||
const LValue *ResultSlot) {
|
||||
const LValue *ResultSlot) {
|
||||
const Expr *Callee = E->getCallee()->IgnoreParens();
|
||||
QualType CalleeType = Callee->getType();
|
||||
|
||||
@ -4597,23 +4597,6 @@ public:
|
||||
auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
|
||||
bool HasQualifier = false;
|
||||
|
||||
struct EvaluateIgnoredRAII {
|
||||
public:
|
||||
EvaluateIgnoredRAII(EvalInfo &Info, llvm::ArrayRef<const Expr*> ToEval)
|
||||
: Info(Info), ToEval(ToEval) {}
|
||||
~EvaluateIgnoredRAII() {
|
||||
if (Info.noteFailure()) {
|
||||
for (auto E : ToEval)
|
||||
EvaluateIgnoredValue(Info, E);
|
||||
}
|
||||
}
|
||||
void cancel() { ToEval = {}; }
|
||||
void drop_front() { ToEval = ToEval.drop_front(); }
|
||||
private:
|
||||
EvalInfo &Info;
|
||||
llvm::ArrayRef<const Expr*> ToEval;
|
||||
} EvalArguments(Info, Args);
|
||||
|
||||
// Extract function decl and 'this' pointer from the callee.
|
||||
if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) {
|
||||
const ValueDecl *Member = nullptr;
|
||||
@ -4663,12 +4646,10 @@ public:
|
||||
if (Args.empty())
|
||||
return Error(E);
|
||||
|
||||
const Expr *FirstArg = Args[0];
|
||||
Args = Args.drop_front();
|
||||
EvalArguments.drop_front();
|
||||
if (!EvaluateObjectArgument(Info, FirstArg, ThisVal))
|
||||
if (!EvaluateObjectArgument(Info, Args[0], ThisVal))
|
||||
return false;
|
||||
This = &ThisVal;
|
||||
Args = Args.slice(1);
|
||||
} else if (MD && MD->isLambdaStaticInvoker()) {
|
||||
// Map the static invoker for the lambda back to the call operator.
|
||||
// Conveniently, we don't have to slice out the 'this' argument (as is
|
||||
@ -4720,12 +4701,8 @@ public:
|
||||
const FunctionDecl *Definition = nullptr;
|
||||
Stmt *Body = FD->getBody(Definition);
|
||||
|
||||
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body))
|
||||
return false;
|
||||
|
||||
EvalArguments.cancel();
|
||||
|
||||
if (!HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info,
|
||||
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) ||
|
||||
!HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info,
|
||||
Result, ResultSlot))
|
||||
return false;
|
||||
|
||||
|
@ -4550,9 +4550,11 @@ CXXNameMangler::makeFunctionReturnTypeTags(const FunctionDecl *FD) {
|
||||
|
||||
const FunctionProtoType *Proto =
|
||||
cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>());
|
||||
FunctionTypeDepthState saved = TrackReturnTypeTags.FunctionTypeDepth.push();
|
||||
TrackReturnTypeTags.FunctionTypeDepth.enterResultType();
|
||||
TrackReturnTypeTags.mangleType(Proto->getReturnType());
|
||||
TrackReturnTypeTags.FunctionTypeDepth.leaveResultType();
|
||||
TrackReturnTypeTags.FunctionTypeDepth.pop(saved);
|
||||
|
||||
return TrackReturnTypeTags.AbiTagsRoot.getSortedUniqueUsedAbiTags();
|
||||
}
|
||||
|
@ -140,7 +140,33 @@ void ODRHash::AddTemplateName(TemplateName Name) {
|
||||
}
|
||||
}
|
||||
|
||||
void ODRHash::AddTemplateArgument(TemplateArgument TA) {}
|
||||
void ODRHash::AddTemplateArgument(TemplateArgument TA) {
|
||||
const auto Kind = TA.getKind();
|
||||
ID.AddInteger(Kind);
|
||||
|
||||
switch (Kind) {
|
||||
case TemplateArgument::Null:
|
||||
case TemplateArgument::Type:
|
||||
case TemplateArgument::Declaration:
|
||||
case TemplateArgument::NullPtr:
|
||||
case TemplateArgument::Integral:
|
||||
break;
|
||||
case TemplateArgument::Template:
|
||||
case TemplateArgument::TemplateExpansion:
|
||||
AddTemplateName(TA.getAsTemplateOrTemplatePattern());
|
||||
break;
|
||||
case TemplateArgument::Expression:
|
||||
AddStmt(TA.getAsExpr());
|
||||
break;
|
||||
case TemplateArgument::Pack:
|
||||
ID.AddInteger(TA.pack_size());
|
||||
for (auto SubTA : TA.pack_elements()) {
|
||||
AddTemplateArgument(SubTA);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {}
|
||||
|
||||
void ODRHash::clear() {
|
||||
@ -226,6 +252,17 @@ public:
|
||||
Inherited::VisitValueDecl(D);
|
||||
}
|
||||
|
||||
void VisitVarDecl(const VarDecl *D) {
|
||||
Hash.AddBoolean(D->isStaticLocal());
|
||||
Hash.AddBoolean(D->isConstexpr());
|
||||
const bool HasInit = D->hasInit();
|
||||
Hash.AddBoolean(HasInit);
|
||||
if (HasInit) {
|
||||
AddStmt(D->getInit());
|
||||
}
|
||||
Inherited::VisitVarDecl(D);
|
||||
}
|
||||
|
||||
void VisitParmVarDecl(const ParmVarDecl *D) {
|
||||
// TODO: Handle default arguments.
|
||||
Inherited::VisitParmVarDecl(D);
|
||||
@ -310,6 +347,7 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) {
|
||||
case Decl::StaticAssert:
|
||||
case Decl::TypeAlias:
|
||||
case Decl::Typedef:
|
||||
case Decl::Var:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -527,6 +565,13 @@ public:
|
||||
Hash.AddTemplateName(T->getTemplateName());
|
||||
VisitType(T);
|
||||
}
|
||||
|
||||
void VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
|
||||
ID.AddInteger(T->getDepth());
|
||||
ID.AddInteger(T->getIndex());
|
||||
Hash.AddBoolean(T->isParameterPack());
|
||||
AddDecl(T->getDecl());
|
||||
}
|
||||
};
|
||||
|
||||
void ODRHash::AddType(const Type *T) {
|
||||
|
@ -964,11 +964,11 @@ Expected<BitcodeModule> clang::FindThinLTOModule(MemoryBufferRef MBRef) {
|
||||
if (!BMsOrErr)
|
||||
return BMsOrErr.takeError();
|
||||
|
||||
// The bitcode file may contain multiple modules, we want the one with a
|
||||
// summary.
|
||||
// The bitcode file may contain multiple modules, we want the one that is
|
||||
// marked as being the ThinLTO module.
|
||||
for (BitcodeModule &BM : *BMsOrErr) {
|
||||
Expected<bool> HasSummary = BM.hasSummary();
|
||||
if (HasSummary && *HasSummary)
|
||||
Expected<BitcodeLTOInfo> LTOInfo = BM.getLTOInfo();
|
||||
if (LTOInfo && LTOInfo->IsThinLTO)
|
||||
return BM;
|
||||
}
|
||||
|
||||
|
@ -7923,6 +7923,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
|
||||
}
|
||||
|
||||
// We can't handle 8-31 immediates with native IR, use the intrinsic.
|
||||
// Except for predicates that create constants.
|
||||
Intrinsic::ID ID;
|
||||
switch (BuiltinID) {
|
||||
default: llvm_unreachable("Unsupported intrinsic!");
|
||||
@ -7930,12 +7931,32 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
|
||||
ID = Intrinsic::x86_sse_cmp_ps;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmpps256:
|
||||
// _CMP_TRUE_UQ, _CMP_TRUE_US produce -1,-1... vector
|
||||
// on any input and _CMP_FALSE_OQ, _CMP_FALSE_OS produce 0, 0...
|
||||
if (CC == 0xf || CC == 0xb || CC == 0x1b || CC == 0x1f) {
|
||||
Value *Constant = (CC == 0xf || CC == 0x1f) ?
|
||||
llvm::Constant::getAllOnesValue(Builder.getInt32Ty()) :
|
||||
llvm::Constant::getNullValue(Builder.getInt32Ty());
|
||||
Value *Vec = Builder.CreateVectorSplat(
|
||||
Ops[0]->getType()->getVectorNumElements(), Constant);
|
||||
return Builder.CreateBitCast(Vec, Ops[0]->getType());
|
||||
}
|
||||
ID = Intrinsic::x86_avx_cmp_ps_256;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmppd:
|
||||
ID = Intrinsic::x86_sse2_cmp_pd;
|
||||
break;
|
||||
case X86::BI__builtin_ia32_cmppd256:
|
||||
// _CMP_TRUE_UQ, _CMP_TRUE_US produce -1,-1... vector
|
||||
// on any input and _CMP_FALSE_OQ, _CMP_FALSE_OS produce 0, 0...
|
||||
if (CC == 0xf || CC == 0xb || CC == 0x1b || CC == 0x1f) {
|
||||
Value *Constant = (CC == 0xf || CC == 0x1f) ?
|
||||
llvm::Constant::getAllOnesValue(Builder.getInt64Ty()) :
|
||||
llvm::Constant::getNullValue(Builder.getInt64Ty());
|
||||
Value *Vec = Builder.CreateVectorSplat(
|
||||
Ops[0]->getType()->getVectorNumElements(), Constant);
|
||||
return Builder.CreateBitCast(Vec, Ops[0]->getType());
|
||||
}
|
||||
ID = Intrinsic::x86_avx_cmp_pd_256;
|
||||
break;
|
||||
}
|
||||
|
@ -1795,6 +1795,8 @@ void CodeGenModule::ConstructAttributeList(
|
||||
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
|
||||
if (TargetDecl->hasAttr<NoReturnAttr>())
|
||||
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
|
||||
if (TargetDecl->hasAttr<ColdAttr>())
|
||||
FuncAttrs.addAttribute(llvm::Attribute::Cold);
|
||||
if (TargetDecl->hasAttr<NoDuplicateAttr>())
|
||||
FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
|
||||
if (TargetDecl->hasAttr<ConvergentAttr>())
|
||||
|
@ -148,25 +148,18 @@ static SmallString<32> buildSuspendPrefixStr(CGCoroData &Coro, AwaitKind Kind) {
|
||||
//
|
||||
// See llvm's docs/Coroutines.rst for more details.
|
||||
//
|
||||
static RValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro,
|
||||
namespace {
|
||||
struct LValueOrRValue {
|
||||
LValue LV;
|
||||
RValue RV;
|
||||
};
|
||||
}
|
||||
static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro,
|
||||
CoroutineSuspendExpr const &S,
|
||||
AwaitKind Kind, AggValueSlot aggSlot,
|
||||
bool ignoreResult) {
|
||||
bool ignoreResult, bool forLValue) {
|
||||
auto *E = S.getCommonExpr();
|
||||
|
||||
// FIXME: rsmith 5/22/2017. Does it still make sense for us to have a
|
||||
// UO_Coawait at all? As I recall, the only purpose it ever had was to
|
||||
// represent a dependent co_await expression that couldn't yet be resolved to
|
||||
// a CoawaitExpr. But now we have (and need!) a separate DependentCoawaitExpr
|
||||
// node to store unqualified lookup results, it seems that the UnaryOperator
|
||||
// portion of the representation serves no purpose (and as seen in this patch,
|
||||
// it's getting in the way). Can we remove it?
|
||||
|
||||
// Skip passthrough operator co_await (present when awaiting on an LValue).
|
||||
if (auto *UO = dyn_cast<UnaryOperator>(E))
|
||||
if (UO->getOpcode() == UO_Coawait)
|
||||
E = UO->getSubExpr();
|
||||
|
||||
auto Binder =
|
||||
CodeGenFunction::OpaqueValueMappingData::bind(CGF, S.getOpaqueValue(), E);
|
||||
auto UnbindOnExit = llvm::make_scope_exit([&] { Binder.unbind(CGF); });
|
||||
@ -217,7 +210,12 @@ static RValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro,
|
||||
|
||||
// Emit await_resume expression.
|
||||
CGF.EmitBlock(ReadyBlock);
|
||||
return CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
|
||||
LValueOrRValue Res;
|
||||
if (forLValue)
|
||||
Res.LV = CGF.EmitLValue(S.getResumeExpr());
|
||||
else
|
||||
Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
|
||||
return Res;
|
||||
}
|
||||
|
||||
RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E,
|
||||
@ -225,13 +223,13 @@ RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E,
|
||||
bool ignoreResult) {
|
||||
return emitSuspendExpression(*this, *CurCoro.Data, E,
|
||||
CurCoro.Data->CurrentAwaitKind, aggSlot,
|
||||
ignoreResult);
|
||||
ignoreResult, /*forLValue*/false).RV;
|
||||
}
|
||||
RValue CodeGenFunction::EmitCoyieldExpr(const CoyieldExpr &E,
|
||||
AggValueSlot aggSlot,
|
||||
bool ignoreResult) {
|
||||
return emitSuspendExpression(*this, *CurCoro.Data, E, AwaitKind::Yield,
|
||||
aggSlot, ignoreResult);
|
||||
aggSlot, ignoreResult, /*forLValue*/false).RV;
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) {
|
||||
@ -240,6 +238,38 @@ void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) {
|
||||
EmitBranchThroughCleanup(CurCoro.Data->FinalJD);
|
||||
}
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
static QualType getCoroutineSuspendExprReturnType(const ASTContext &Ctx,
|
||||
const CoroutineSuspendExpr *E) {
|
||||
const auto *RE = E->getResumeExpr();
|
||||
// Is it possible for RE to be a CXXBindTemporaryExpr wrapping
|
||||
// a MemberCallExpr?
|
||||
assert(isa<CallExpr>(RE) && "unexpected suspend expression type");
|
||||
return cast<CallExpr>(RE)->getCallReturnType(Ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
LValue
|
||||
CodeGenFunction::EmitCoawaitLValue(const CoawaitExpr *E) {
|
||||
assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() &&
|
||||
"Can't have a scalar return unless the return type is a "
|
||||
"reference type!");
|
||||
return emitSuspendExpression(*this, *CurCoro.Data, *E,
|
||||
CurCoro.Data->CurrentAwaitKind, AggValueSlot::ignored(),
|
||||
/*ignoreResult*/false, /*forLValue*/true).LV;
|
||||
}
|
||||
|
||||
LValue
|
||||
CodeGenFunction::EmitCoyieldLValue(const CoyieldExpr *E) {
|
||||
assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() &&
|
||||
"Can't have a scalar return unless the return type is a "
|
||||
"reference type!");
|
||||
return emitSuspendExpression(*this, *CurCoro.Data, *E,
|
||||
AwaitKind::Yield, AggValueSlot::ignored(),
|
||||
/*ignoreResult*/false, /*forLValue*/true).LV;
|
||||
}
|
||||
|
||||
// Hunts for the parameter reference in the parameter copy/move declaration.
|
||||
namespace {
|
||||
struct GetParamRef : public StmtVisitor<GetParamRef> {
|
||||
|
@ -1041,7 +1041,13 @@ llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl,
|
||||
assert(SizeInBits > 0 && "found named 0-width bitfield");
|
||||
uint64_t StorageOffsetInBits =
|
||||
CGM.getContext().toBits(BitFieldInfo.StorageOffset);
|
||||
uint64_t OffsetInBits = StorageOffsetInBits + BitFieldInfo.Offset;
|
||||
uint64_t Offset = BitFieldInfo.Offset;
|
||||
// The bit offsets for big endian machines are reversed for big
|
||||
// endian target, compensate for that as the DIDerivedType requires
|
||||
// un-reversed offsets.
|
||||
if (CGM.getDataLayout().isBigEndian())
|
||||
Offset = BitFieldInfo.StorageSize - BitFieldInfo.Size - Offset;
|
||||
uint64_t OffsetInBits = StorageOffsetInBits + Offset;
|
||||
llvm::DINode::DIFlags Flags = getAccessFlag(BitFieldDecl->getAccess(), RD);
|
||||
return DBuilder.createBitFieldMemberType(
|
||||
RecordTy, Name, File, Line, SizeInBits, OffsetInBits, StorageOffsetInBits,
|
||||
@ -3484,13 +3490,13 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage,
|
||||
if (VD->hasAttr<BlocksAttr>()) {
|
||||
// Here, we need an offset *into* the alloca.
|
||||
CharUnits offset = CharUnits::fromQuantity(32);
|
||||
Expr.push_back(llvm::dwarf::DW_OP_plus);
|
||||
Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
|
||||
// offset of __forwarding field
|
||||
offset = CGM.getContext().toCharUnitsFromBits(
|
||||
CGM.getTarget().getPointerWidth(0));
|
||||
Expr.push_back(offset.getQuantity());
|
||||
Expr.push_back(llvm::dwarf::DW_OP_deref);
|
||||
Expr.push_back(llvm::dwarf::DW_OP_plus);
|
||||
Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
|
||||
// offset of x field
|
||||
offset = CGM.getContext().toCharUnitsFromBits(XOffset);
|
||||
Expr.push_back(offset.getQuantity());
|
||||
@ -3599,17 +3605,17 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
|
||||
|
||||
SmallVector<int64_t, 9> addr;
|
||||
addr.push_back(llvm::dwarf::DW_OP_deref);
|
||||
addr.push_back(llvm::dwarf::DW_OP_plus);
|
||||
addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
|
||||
addr.push_back(offset.getQuantity());
|
||||
if (isByRef) {
|
||||
addr.push_back(llvm::dwarf::DW_OP_deref);
|
||||
addr.push_back(llvm::dwarf::DW_OP_plus);
|
||||
addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
|
||||
// offset of __forwarding field
|
||||
offset =
|
||||
CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits(0));
|
||||
addr.push_back(offset.getQuantity());
|
||||
addr.push_back(llvm::dwarf::DW_OP_deref);
|
||||
addr.push_back(llvm::dwarf::DW_OP_plus);
|
||||
addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
|
||||
// offset of x field
|
||||
offset = CGM.getContext().toCharUnitsFromBits(XOffset);
|
||||
addr.push_back(offset.getQuantity());
|
||||
|
@ -549,6 +549,11 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
|
||||
if (Ptr->getType()->getPointerAddressSpace())
|
||||
return;
|
||||
|
||||
// Don't check pointers to volatile data. The behavior here is implementation-
|
||||
// defined.
|
||||
if (Ty.isVolatileQualified())
|
||||
return;
|
||||
|
||||
SanitizerScope SanScope(this);
|
||||
|
||||
SmallVector<std::pair<llvm::Value *, SanitizerMask>, 3> Checks;
|
||||
@ -1158,6 +1163,11 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
|
||||
|
||||
case Expr::MaterializeTemporaryExprClass:
|
||||
return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
|
||||
|
||||
case Expr::CoawaitExprClass:
|
||||
return EmitCoawaitLValue(cast<CoawaitExpr>(E));
|
||||
case Expr::CoyieldExprClass:
|
||||
return EmitCoyieldLValue(cast<CoyieldExpr>(E));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3002,10 +3012,11 @@ static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF,
|
||||
llvm::Value *ptr,
|
||||
ArrayRef<llvm::Value*> indices,
|
||||
bool inbounds,
|
||||
bool signedIndices,
|
||||
SourceLocation loc,
|
||||
const llvm::Twine &name = "arrayidx") {
|
||||
if (inbounds) {
|
||||
return CGF.EmitCheckedInBoundsGEP(ptr, indices, loc, name);
|
||||
return CGF.EmitCheckedInBoundsGEP(ptr, indices, signedIndices, loc, name);
|
||||
} else {
|
||||
return CGF.Builder.CreateGEP(ptr, indices, name);
|
||||
}
|
||||
@ -3038,7 +3049,7 @@ static QualType getFixedSizeElementType(const ASTContext &ctx,
|
||||
static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
|
||||
ArrayRef<llvm::Value *> indices,
|
||||
QualType eltType, bool inbounds,
|
||||
SourceLocation loc,
|
||||
bool signedIndices, SourceLocation loc,
|
||||
const llvm::Twine &name = "arrayidx") {
|
||||
// All the indices except that last must be zero.
|
||||
#ifndef NDEBUG
|
||||
@ -3058,8 +3069,8 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
|
||||
CharUnits eltAlign =
|
||||
getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize);
|
||||
|
||||
llvm::Value *eltPtr =
|
||||
emitArraySubscriptGEP(CGF, addr.getPointer(), indices, inbounds, loc, name);
|
||||
llvm::Value *eltPtr = emitArraySubscriptGEP(
|
||||
CGF, addr.getPointer(), indices, inbounds, signedIndices, loc, name);
|
||||
return Address(eltPtr, eltAlign);
|
||||
}
|
||||
|
||||
@ -3069,6 +3080,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
|
||||
// in lexical order (this complexity is, sadly, required by C++17).
|
||||
llvm::Value *IdxPre =
|
||||
(E->getLHS() == E->getIdx()) ? EmitScalarExpr(E->getIdx()) : nullptr;
|
||||
bool SignedIndices = false;
|
||||
auto EmitIdxAfterBase = [&, IdxPre](bool Promote) -> llvm::Value * {
|
||||
auto *Idx = IdxPre;
|
||||
if (E->getLHS() != E->getIdx()) {
|
||||
@ -3078,6 +3090,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
|
||||
|
||||
QualType IdxTy = E->getIdx()->getType();
|
||||
bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
|
||||
SignedIndices |= IdxSigned;
|
||||
|
||||
if (SanOpts.has(SanitizerKind::ArrayBounds))
|
||||
EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed);
|
||||
@ -3113,7 +3126,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
|
||||
|
||||
QualType EltType = LV.getType()->castAs<VectorType>()->getElementType();
|
||||
Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true,
|
||||
E->getExprLoc());
|
||||
SignedIndices, E->getExprLoc());
|
||||
return MakeAddrLValue(Addr, EltType, LV.getBaseInfo());
|
||||
}
|
||||
|
||||
@ -3142,7 +3155,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
|
||||
|
||||
Addr = emitArraySubscriptGEP(*this, Addr, Idx, vla->getElementType(),
|
||||
!getLangOpts().isSignedOverflowDefined(),
|
||||
E->getExprLoc());
|
||||
SignedIndices, E->getExprLoc());
|
||||
|
||||
} else if (const ObjCObjectType *OIT = E->getType()->getAs<ObjCObjectType>()){
|
||||
// Indexing over an interface, as in "NSString *P; P[4];"
|
||||
@ -3167,8 +3180,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
|
||||
// Do the GEP.
|
||||
CharUnits EltAlign =
|
||||
getArrayElementAlign(Addr.getAlignment(), Idx, InterfaceSize);
|
||||
llvm::Value *EltPtr = emitArraySubscriptGEP(
|
||||
*this, Addr.getPointer(), ScaledIdx, false, E->getExprLoc());
|
||||
llvm::Value *EltPtr =
|
||||
emitArraySubscriptGEP(*this, Addr.getPointer(), ScaledIdx, false,
|
||||
SignedIndices, E->getExprLoc());
|
||||
Addr = Address(EltPtr, EltAlign);
|
||||
|
||||
// Cast back.
|
||||
@ -3190,11 +3204,10 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
|
||||
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
|
||||
|
||||
// Propagate the alignment from the array itself to the result.
|
||||
Addr = emitArraySubscriptGEP(*this, ArrayLV.getAddress(),
|
||||
{CGM.getSize(CharUnits::Zero()), Idx},
|
||||
E->getType(),
|
||||
!getLangOpts().isSignedOverflowDefined(),
|
||||
E->getExprLoc());
|
||||
Addr = emitArraySubscriptGEP(
|
||||
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
|
||||
E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices,
|
||||
E->getExprLoc());
|
||||
BaseInfo = ArrayLV.getBaseInfo();
|
||||
} else {
|
||||
// The base must be a pointer; emit it with an estimate of its alignment.
|
||||
@ -3202,7 +3215,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
|
||||
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
|
||||
Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),
|
||||
!getLangOpts().isSignedOverflowDefined(),
|
||||
E->getExprLoc());
|
||||
SignedIndices, E->getExprLoc());
|
||||
}
|
||||
|
||||
LValue LV = MakeAddrLValue(Addr, E->getType(), BaseInfo);
|
||||
@ -3375,7 +3388,7 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
|
||||
Idx = Builder.CreateNSWMul(Idx, NumElements);
|
||||
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, VLA->getElementType(),
|
||||
!getLangOpts().isSignedOverflowDefined(),
|
||||
E->getExprLoc());
|
||||
/*SignedIndices=*/false, E->getExprLoc());
|
||||
} else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) {
|
||||
// If this is A[i] where A is an array, the frontend will have decayed the
|
||||
// base to be a ArrayToPointerDecay implicit cast. While correct, it is
|
||||
@ -3395,14 +3408,14 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
|
||||
EltPtr = emitArraySubscriptGEP(
|
||||
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
|
||||
ResultExprTy, !getLangOpts().isSignedOverflowDefined(),
|
||||
E->getExprLoc());
|
||||
/*SignedIndices=*/false, E->getExprLoc());
|
||||
BaseInfo = ArrayLV.getBaseInfo();
|
||||
} else {
|
||||
Address Base = emitOMPArraySectionBase(*this, E->getBase(), BaseInfo,
|
||||
BaseTy, ResultExprTy, IsLowerBound);
|
||||
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy,
|
||||
!getLangOpts().isSignedOverflowDefined(),
|
||||
E->getExprLoc());
|
||||
/*SignedIndices=*/false, E->getExprLoc());
|
||||
}
|
||||
|
||||
return MakeAddrLValue(EltPtr, ResultExprTy, BaseInfo);
|
||||
|
@ -1851,6 +1851,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||
llvm::Value *input;
|
||||
|
||||
int amount = (isInc ? 1 : -1);
|
||||
bool signedIndex = !isInc;
|
||||
|
||||
if (const AtomicType *atomicTy = type->getAs<AtomicType>()) {
|
||||
type = atomicTy->getValueType();
|
||||
@ -1940,8 +1941,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||
if (CGF.getLangOpts().isSignedOverflowDefined())
|
||||
value = Builder.CreateGEP(value, numElts, "vla.inc");
|
||||
else
|
||||
value = CGF.EmitCheckedInBoundsGEP(value, numElts, E->getExprLoc(),
|
||||
"vla.inc");
|
||||
value = CGF.EmitCheckedInBoundsGEP(value, numElts, signedIndex,
|
||||
E->getExprLoc(), "vla.inc");
|
||||
|
||||
// Arithmetic on function pointers (!) is just +-1.
|
||||
} else if (type->isFunctionType()) {
|
||||
@ -1951,8 +1952,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||
if (CGF.getLangOpts().isSignedOverflowDefined())
|
||||
value = Builder.CreateGEP(value, amt, "incdec.funcptr");
|
||||
else
|
||||
value = CGF.EmitCheckedInBoundsGEP(value, amt, E->getExprLoc(),
|
||||
"incdec.funcptr");
|
||||
value = CGF.EmitCheckedInBoundsGEP(value, amt, signedIndex,
|
||||
E->getExprLoc(), "incdec.funcptr");
|
||||
value = Builder.CreateBitCast(value, input->getType());
|
||||
|
||||
// For everything else, we can just do a simple increment.
|
||||
@ -1961,8 +1962,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||
if (CGF.getLangOpts().isSignedOverflowDefined())
|
||||
value = Builder.CreateGEP(value, amt, "incdec.ptr");
|
||||
else
|
||||
value = CGF.EmitCheckedInBoundsGEP(value, amt, E->getExprLoc(),
|
||||
"incdec.ptr");
|
||||
value = CGF.EmitCheckedInBoundsGEP(value, amt, signedIndex,
|
||||
E->getExprLoc(), "incdec.ptr");
|
||||
}
|
||||
|
||||
// Vector increment/decrement.
|
||||
@ -2043,8 +2044,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||
if (CGF.getLangOpts().isSignedOverflowDefined())
|
||||
value = Builder.CreateGEP(value, sizeValue, "incdec.objptr");
|
||||
else
|
||||
value = CGF.EmitCheckedInBoundsGEP(value, sizeValue, E->getExprLoc(),
|
||||
"incdec.objptr");
|
||||
value = CGF.EmitCheckedInBoundsGEP(value, sizeValue, signedIndex,
|
||||
E->getExprLoc(), "incdec.objptr");
|
||||
value = Builder.CreateBitCast(value, input->getType());
|
||||
}
|
||||
|
||||
@ -2661,13 +2662,15 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
|
||||
std::swap(pointerOperand, indexOperand);
|
||||
}
|
||||
|
||||
bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
|
||||
bool mayHaveNegativeGEPIndex = isSigned || isSubtraction;
|
||||
|
||||
unsigned width = cast<llvm::IntegerType>(index->getType())->getBitWidth();
|
||||
auto &DL = CGF.CGM.getDataLayout();
|
||||
auto PtrTy = cast<llvm::PointerType>(pointer->getType());
|
||||
if (width != DL.getTypeSizeInBits(PtrTy)) {
|
||||
// Zero-extend or sign-extend the pointer value according to
|
||||
// whether the index is signed or not.
|
||||
bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
|
||||
index = CGF.Builder.CreateIntCast(index, DL.getIntPtrType(PtrTy), isSigned,
|
||||
"idx.ext");
|
||||
}
|
||||
@ -2711,8 +2714,9 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
|
||||
pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr");
|
||||
} else {
|
||||
index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index");
|
||||
pointer = CGF.EmitCheckedInBoundsGEP(pointer, index, op.E->getExprLoc(),
|
||||
"add.ptr");
|
||||
pointer =
|
||||
CGF.EmitCheckedInBoundsGEP(pointer, index, mayHaveNegativeGEPIndex,
|
||||
op.E->getExprLoc(), "add.ptr");
|
||||
}
|
||||
return pointer;
|
||||
}
|
||||
@ -2729,8 +2733,8 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
|
||||
if (CGF.getLangOpts().isSignedOverflowDefined())
|
||||
return CGF.Builder.CreateGEP(pointer, index, "add.ptr");
|
||||
|
||||
return CGF.EmitCheckedInBoundsGEP(pointer, index, op.E->getExprLoc(),
|
||||
"add.ptr");
|
||||
return CGF.EmitCheckedInBoundsGEP(pointer, index, mayHaveNegativeGEPIndex,
|
||||
op.E->getExprLoc(), "add.ptr");
|
||||
}
|
||||
|
||||
// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and
|
||||
@ -3848,6 +3852,7 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue(
|
||||
|
||||
Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
|
||||
ArrayRef<Value *> IdxList,
|
||||
bool SignedIndices,
|
||||
SourceLocation Loc,
|
||||
const Twine &Name) {
|
||||
Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name);
|
||||
@ -3905,7 +3910,7 @@ Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
|
||||
auto *ResultAndOverflow = Builder.CreateCall(
|
||||
(Opcode == BO_Add) ? SAddIntrinsic : SMulIntrinsic, {LHS, RHS});
|
||||
OffsetOverflows = Builder.CreateOr(
|
||||
OffsetOverflows, Builder.CreateExtractValue(ResultAndOverflow, 1));
|
||||
Builder.CreateExtractValue(ResultAndOverflow, 1), OffsetOverflows);
|
||||
return Builder.CreateExtractValue(ResultAndOverflow, 0);
|
||||
};
|
||||
|
||||
@ -3951,12 +3956,18 @@ Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
|
||||
// 1) The total offset doesn't overflow, and
|
||||
// 2) The sign of the difference between the computed address and the base
|
||||
// pointer matches the sign of the total offset.
|
||||
llvm::Value *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
|
||||
llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr);
|
||||
auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero);
|
||||
llvm::Value *ValidGEP = Builder.CreateAnd(
|
||||
Builder.CreateNot(OffsetOverflows),
|
||||
Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid));
|
||||
llvm::Value *ValidGEP;
|
||||
auto *NoOffsetOverflow = Builder.CreateNot(OffsetOverflows);
|
||||
auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
|
||||
if (SignedIndices) {
|
||||
auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero);
|
||||
llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr);
|
||||
ValidGEP = Builder.CreateAnd(
|
||||
Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid),
|
||||
NoOffsetOverflow);
|
||||
} else {
|
||||
ValidGEP = Builder.CreateAnd(PosOrZeroValid, NoOffsetOverflow);
|
||||
}
|
||||
|
||||
llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)};
|
||||
// Pass the computed GEP to the runtime to avoid emitting poisoned arguments.
|
||||
|
@ -6327,7 +6327,7 @@ bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) {
|
||||
}
|
||||
}
|
||||
|
||||
// If we are in target mode we do not emit any global (declare target is not
|
||||
// If we are in target mode, we do not emit any global (declare target is not
|
||||
// implemented yet). Therefore we signal that GD was processed in this case.
|
||||
return true;
|
||||
}
|
||||
|
@ -2550,9 +2550,11 @@ public:
|
||||
RValue EmitCoawaitExpr(const CoawaitExpr &E,
|
||||
AggValueSlot aggSlot = AggValueSlot::ignored(),
|
||||
bool ignoreResult = false);
|
||||
LValue EmitCoawaitLValue(const CoawaitExpr *E);
|
||||
RValue EmitCoyieldExpr(const CoyieldExpr &E,
|
||||
AggValueSlot aggSlot = AggValueSlot::ignored(),
|
||||
bool ignoreResult = false);
|
||||
LValue EmitCoyieldLValue(const CoyieldExpr *E);
|
||||
RValue EmitCoroutineIntrinsic(const CallExpr *E, unsigned int IID);
|
||||
|
||||
void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
|
||||
@ -3554,8 +3556,10 @@ public:
|
||||
|
||||
/// Same as IRBuilder::CreateInBoundsGEP, but additionally emits a check to
|
||||
/// detect undefined behavior when the pointer overflow sanitizer is enabled.
|
||||
/// \p SignedIndices indicates whether any of the GEP indices are signed.
|
||||
llvm::Value *EmitCheckedInBoundsGEP(llvm::Value *Ptr,
|
||||
ArrayRef<llvm::Value *> IdxList,
|
||||
bool SignedIndices,
|
||||
SourceLocation Loc,
|
||||
const Twine &Name = "");
|
||||
|
||||
|
@ -1243,7 +1243,7 @@ void CodeGenModule::AddDependentLib(StringRef Lib) {
|
||||
/// \brief Add link options implied by the given module, including modules
|
||||
/// it depends on, using a postorder walk.
|
||||
static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod,
|
||||
SmallVectorImpl<llvm::Metadata *> &Metadata,
|
||||
SmallVectorImpl<llvm::MDNode *> &Metadata,
|
||||
llvm::SmallPtrSet<Module *, 16> &Visited) {
|
||||
// Import this module's parent.
|
||||
if (Mod->Parent && Visited.insert(Mod->Parent).second) {
|
||||
@ -1331,7 +1331,7 @@ void CodeGenModule::EmitModuleLinkOptions() {
|
||||
// Add link options for all of the imported modules in reverse topological
|
||||
// order. We don't do anything to try to order import link flags with respect
|
||||
// to linker options inserted by things like #pragma comment().
|
||||
SmallVector<llvm::Metadata *, 16> MetadataArgs;
|
||||
SmallVector<llvm::MDNode *, 16> MetadataArgs;
|
||||
Visited.clear();
|
||||
for (Module *M : LinkModules)
|
||||
if (Visited.insert(M).second)
|
||||
@ -1340,9 +1340,9 @@ void CodeGenModule::EmitModuleLinkOptions() {
|
||||
LinkerOptionsMetadata.append(MetadataArgs.begin(), MetadataArgs.end());
|
||||
|
||||
// Add the linker options metadata flag.
|
||||
getModule().addModuleFlag(llvm::Module::AppendUnique, "Linker Options",
|
||||
llvm::MDNode::get(getLLVMContext(),
|
||||
LinkerOptionsMetadata));
|
||||
auto *NMD = getModule().getOrInsertNamedMetadata("llvm.linker.options");
|
||||
for (auto *MD : LinkerOptionsMetadata)
|
||||
NMD->addOperand(MD);
|
||||
}
|
||||
|
||||
void CodeGenModule::EmitDeferred() {
|
||||
|
@ -429,7 +429,7 @@ private:
|
||||
llvm::SmallPtrSet<clang::Module *, 16> EmittedModuleInitializers;
|
||||
|
||||
/// \brief A vector of metadata strings.
|
||||
SmallVector<llvm::Metadata *, 16> LinkerOptionsMetadata;
|
||||
SmallVector<llvm::MDNode *, 16> LinkerOptionsMetadata;
|
||||
|
||||
/// @name Cache for Objective-C runtime types
|
||||
/// @{
|
||||
@ -1058,13 +1058,14 @@ public:
|
||||
|
||||
void RefreshTypeCacheForClass(const CXXRecordDecl *Class);
|
||||
|
||||
/// \brief Appends Opts to the "Linker Options" metadata value.
|
||||
/// \brief Appends Opts to the "llvm.linker.options" metadata value.
|
||||
void AppendLinkerOptions(StringRef Opts);
|
||||
|
||||
/// \brief Appends a detect mismatch command to the linker options.
|
||||
void AddDetectMismatch(StringRef Name, StringRef Value);
|
||||
|
||||
/// \brief Appends a dependent lib to the "Linker Options" metadata value.
|
||||
/// \brief Appends a dependent lib to the "llvm.linker.options" metadata
|
||||
/// value.
|
||||
void AddDependentLib(StringRef Lib);
|
||||
|
||||
llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD);
|
||||
|
@ -980,6 +980,9 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
|
||||
DepTarget = Args.MakeArgString(llvm::sys::path::filename(P));
|
||||
}
|
||||
|
||||
if (!A->getOption().matches(options::OPT_MD) && !A->getOption().matches(options::OPT_MMD)) {
|
||||
CmdArgs.push_back("-w");
|
||||
}
|
||||
CmdArgs.push_back("-MT");
|
||||
SmallString<128> Quoted;
|
||||
QuoteTarget(DepTarget, Quoted);
|
||||
|
@ -310,6 +310,8 @@ template <> struct MappingTraits<FormatStyle> {
|
||||
IO.mapOptional("BreakBeforeBinaryOperators",
|
||||
Style.BreakBeforeBinaryOperators);
|
||||
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
|
||||
IO.mapOptional("BreakBeforeInheritanceComma",
|
||||
Style.BreakBeforeInheritanceComma);
|
||||
IO.mapOptional("BreakBeforeTernaryOperators",
|
||||
Style.BreakBeforeTernaryOperators);
|
||||
|
||||
@ -330,8 +332,7 @@ template <> struct MappingTraits<FormatStyle> {
|
||||
IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
|
||||
IO.mapOptional("ColumnLimit", Style.ColumnLimit);
|
||||
IO.mapOptional("CommentPragmas", Style.CommentPragmas);
|
||||
IO.mapOptional("BreakBeforeInheritanceComma",
|
||||
Style.BreakBeforeInheritanceComma);
|
||||
IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
|
||||
IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
|
||||
Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
|
||||
IO.mapOptional("ConstructorInitializerIndentWidth",
|
||||
@ -410,6 +411,7 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
|
||||
IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch);
|
||||
IO.mapOptional("BeforeElse", Wrapping.BeforeElse);
|
||||
IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
|
||||
IO.mapOptional("SplitEmptyFunctionBody", Wrapping.SplitEmptyFunctionBody);
|
||||
}
|
||||
};
|
||||
|
||||
@ -485,7 +487,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
|
||||
return Style;
|
||||
FormatStyle Expanded = Style;
|
||||
Expanded.BraceWrapping = {false, false, false, false, false, false,
|
||||
false, false, false, false, false};
|
||||
false, false, false, false, false, true};
|
||||
switch (Style.BreakBeforeBraces) {
|
||||
case FormatStyle::BS_Linux:
|
||||
Expanded.BraceWrapping.AfterClass = true;
|
||||
@ -498,6 +500,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
|
||||
Expanded.BraceWrapping.AfterFunction = true;
|
||||
Expanded.BraceWrapping.AfterStruct = true;
|
||||
Expanded.BraceWrapping.AfterUnion = true;
|
||||
Expanded.BraceWrapping.SplitEmptyFunctionBody = false;
|
||||
break;
|
||||
case FormatStyle::BS_Stroustrup:
|
||||
Expanded.BraceWrapping.AfterFunction = true;
|
||||
@ -517,7 +520,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
|
||||
break;
|
||||
case FormatStyle::BS_GNU:
|
||||
Expanded.BraceWrapping = {true, true, true, true, true, true,
|
||||
true, true, true, true, true};
|
||||
true, true, true, true, true, true};
|
||||
break;
|
||||
case FormatStyle::BS_WebKit:
|
||||
Expanded.BraceWrapping.AfterFunction = true;
|
||||
@ -548,19 +551,20 @@ FormatStyle getLLVMStyle() {
|
||||
LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
|
||||
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
|
||||
LLVMStyle.AlwaysBreakTemplateDeclarations = false;
|
||||
LLVMStyle.BinPackParameters = true;
|
||||
LLVMStyle.BinPackArguments = true;
|
||||
LLVMStyle.BinPackParameters = true;
|
||||
LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
|
||||
LLVMStyle.BreakBeforeTernaryOperators = true;
|
||||
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
|
||||
LLVMStyle.BraceWrapping = {false, false, false, false, false, false,
|
||||
false, false, false, false, false};
|
||||
false, false, false, false, false, true};
|
||||
LLVMStyle.BreakAfterJavaFieldAnnotations = false;
|
||||
LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
|
||||
LLVMStyle.BreakBeforeInheritanceComma = false;
|
||||
LLVMStyle.BreakStringLiterals = true;
|
||||
LLVMStyle.ColumnLimit = 80;
|
||||
LLVMStyle.CommentPragmas = "^ IWYU pragma:";
|
||||
LLVMStyle.CompactNamespaces = false;
|
||||
LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
|
||||
LLVMStyle.ConstructorInitializerIndentWidth = 4;
|
||||
LLVMStyle.ContinuationIndentWidth = 4;
|
||||
|
@ -107,6 +107,24 @@ void updateEndComment(const FormatToken *RBraceTok, StringRef EndCommentText,
|
||||
<< llvm::toString(std::move(Err)) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
const FormatToken *
|
||||
getNamespaceToken(const AnnotatedLine *line,
|
||||
const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
|
||||
if (!line->Affected || line->InPPDirective || !line->startsWith(tok::r_brace))
|
||||
return nullptr;
|
||||
size_t StartLineIndex = line->MatchingOpeningBlockLineIndex;
|
||||
if (StartLineIndex == UnwrappedLine::kInvalidIndex)
|
||||
return nullptr;
|
||||
assert(StartLineIndex < AnnotatedLines.size());
|
||||
const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First;
|
||||
// Detect "(inline)? namespace" in the beginning of a line.
|
||||
if (NamespaceTok->is(tok::kw_inline))
|
||||
NamespaceTok = NamespaceTok->getNextNonComment();
|
||||
if (!NamespaceTok || NamespaceTok->isNot(tok::kw_namespace))
|
||||
return nullptr;
|
||||
return NamespaceTok;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env,
|
||||
@ -120,20 +138,14 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze(
|
||||
AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
|
||||
AnnotatedLines.end());
|
||||
tooling::Replacements Fixes;
|
||||
std::string AllNamespaceNames = "";
|
||||
size_t StartLineIndex = SIZE_MAX;
|
||||
unsigned int CompactedNamespacesCount = 0;
|
||||
for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
|
||||
if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective ||
|
||||
!AnnotatedLines[I]->startsWith(tok::r_brace))
|
||||
continue;
|
||||
const AnnotatedLine *EndLine = AnnotatedLines[I];
|
||||
size_t StartLineIndex = EndLine->MatchingOpeningBlockLineIndex;
|
||||
if (StartLineIndex == UnwrappedLine::kInvalidIndex)
|
||||
continue;
|
||||
assert(StartLineIndex < E);
|
||||
const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First;
|
||||
// Detect "(inline)? namespace" in the beginning of a line.
|
||||
if (NamespaceTok->is(tok::kw_inline))
|
||||
NamespaceTok = NamespaceTok->getNextNonComment();
|
||||
if (!NamespaceTok || NamespaceTok->isNot(tok::kw_namespace))
|
||||
const FormatToken *NamespaceTok =
|
||||
getNamespaceToken(EndLine, AnnotatedLines);
|
||||
if (!NamespaceTok)
|
||||
continue;
|
||||
FormatToken *RBraceTok = EndLine->First;
|
||||
if (RBraceTok->Finalized)
|
||||
@ -145,6 +157,27 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze(
|
||||
if (RBraceTok->Next && RBraceTok->Next->is(tok::semi)) {
|
||||
EndCommentPrevTok = RBraceTok->Next;
|
||||
}
|
||||
if (StartLineIndex == SIZE_MAX)
|
||||
StartLineIndex = EndLine->MatchingOpeningBlockLineIndex;
|
||||
std::string NamespaceName = computeName(NamespaceTok);
|
||||
if (Style.CompactNamespaces) {
|
||||
if ((I + 1 < E) &&
|
||||
getNamespaceToken(AnnotatedLines[I + 1], AnnotatedLines) &&
|
||||
StartLineIndex - CompactedNamespacesCount - 1 ==
|
||||
AnnotatedLines[I + 1]->MatchingOpeningBlockLineIndex &&
|
||||
!AnnotatedLines[I + 1]->First->Finalized) {
|
||||
if (hasEndComment(EndCommentPrevTok)) {
|
||||
// remove end comment, it will be merged in next one
|
||||
updateEndComment(EndCommentPrevTok, std::string(), SourceMgr, &Fixes);
|
||||
}
|
||||
CompactedNamespacesCount++;
|
||||
AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames;
|
||||
continue;
|
||||
}
|
||||
NamespaceName += std::move(AllNamespaceNames);
|
||||
CompactedNamespacesCount = 0;
|
||||
AllNamespaceNames = std::string();
|
||||
}
|
||||
// The next token in the token stream after the place where the end comment
|
||||
// token must be. This is either the next token on the current line or the
|
||||
// first token on the next line.
|
||||
@ -156,17 +189,16 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze(
|
||||
bool AddNewline = EndCommentNextTok &&
|
||||
EndCommentNextTok->NewlinesBefore == 0 &&
|
||||
EndCommentNextTok->isNot(tok::eof);
|
||||
const std::string NamespaceName = computeName(NamespaceTok);
|
||||
const std::string EndCommentText =
|
||||
computeEndCommentText(NamespaceName, AddNewline);
|
||||
if (!hasEndComment(EndCommentPrevTok)) {
|
||||
bool isShort = I - StartLineIndex <= kShortNamespaceMaxLines + 1;
|
||||
if (!isShort)
|
||||
addEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
|
||||
continue;
|
||||
}
|
||||
if (!validEndComment(EndCommentPrevTok, NamespaceName))
|
||||
} else if (!validEndComment(EndCommentPrevTok, NamespaceName)) {
|
||||
updateEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
|
||||
}
|
||||
StartLineIndex = SIZE_MAX;
|
||||
}
|
||||
return Fixes;
|
||||
}
|
||||
|
@ -66,6 +66,13 @@ public:
|
||||
Indent += Offset;
|
||||
}
|
||||
|
||||
/// \brief Update the indent state given that \p Line indent should be
|
||||
/// skipped.
|
||||
void skipLine(const AnnotatedLine &Line) {
|
||||
while (IndentForLevel.size() <= Line.Level)
|
||||
IndentForLevel.push_back(Indent);
|
||||
}
|
||||
|
||||
/// \brief Update the level indent to adapt to the given \p Line.
|
||||
///
|
||||
/// When a line is not formatted, we move the subsequent lines on the same
|
||||
@ -127,12 +134,31 @@ private:
|
||||
unsigned Indent = 0;
|
||||
};
|
||||
|
||||
bool isNamespaceDeclaration(const AnnotatedLine *Line) {
|
||||
const FormatToken *NamespaceTok = Line->First;
|
||||
// Detect "(inline)? namespace" in the beginning of a line.
|
||||
if (NamespaceTok->is(tok::kw_inline))
|
||||
NamespaceTok = NamespaceTok->getNextNonComment();
|
||||
return NamespaceTok && NamespaceTok->is(tok::kw_namespace);
|
||||
}
|
||||
|
||||
bool isEndOfNamespace(const AnnotatedLine *Line,
|
||||
const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
|
||||
if (!Line->startsWith(tok::r_brace))
|
||||
return false;
|
||||
size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex;
|
||||
if (StartLineIndex == UnwrappedLine::kInvalidIndex)
|
||||
return false;
|
||||
assert(StartLineIndex < AnnotatedLines.size());
|
||||
return isNamespaceDeclaration(AnnotatedLines[StartLineIndex]);
|
||||
}
|
||||
|
||||
class LineJoiner {
|
||||
public:
|
||||
LineJoiner(const FormatStyle &Style, const AdditionalKeywords &Keywords,
|
||||
const SmallVectorImpl<AnnotatedLine *> &Lines)
|
||||
: Style(Style), Keywords(Keywords), End(Lines.end()),
|
||||
Next(Lines.begin()) {}
|
||||
: Style(Style), Keywords(Keywords), End(Lines.end()), Next(Lines.begin()),
|
||||
AnnotatedLines(Lines) {}
|
||||
|
||||
/// \brief Returns the next line, merging multiple lines into one if possible.
|
||||
const AnnotatedLine *getNextMergedLine(bool DryRun,
|
||||
@ -142,7 +168,7 @@ public:
|
||||
const AnnotatedLine *Current = *Next;
|
||||
IndentTracker.nextLine(*Current);
|
||||
unsigned MergedLines =
|
||||
tryFitMultipleLinesInOne(IndentTracker.getIndent(), Next, End);
|
||||
tryFitMultipleLinesInOne(IndentTracker, Next, End);
|
||||
if (MergedLines > 0 && Style.ColumnLimit == 0)
|
||||
// Disallow line merging if there is a break at the start of one of the
|
||||
// input lines.
|
||||
@ -159,9 +185,11 @@ public:
|
||||
private:
|
||||
/// \brief Calculates how many lines can be merged into 1 starting at \p I.
|
||||
unsigned
|
||||
tryFitMultipleLinesInOne(unsigned Indent,
|
||||
tryFitMultipleLinesInOne(LevelIndentTracker &IndentTracker,
|
||||
SmallVectorImpl<AnnotatedLine *>::const_iterator I,
|
||||
SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
|
||||
const unsigned Indent = IndentTracker.getIndent();
|
||||
|
||||
// Can't join the last line with anything.
|
||||
if (I + 1 == E)
|
||||
return 0;
|
||||
@ -186,6 +214,12 @@ private:
|
||||
? 0
|
||||
: Limit - TheLine->Last->TotalLength;
|
||||
|
||||
if (TheLine->Last->is(TT_FunctionLBrace) &&
|
||||
TheLine->First == TheLine->Last &&
|
||||
!Style.BraceWrapping.SplitEmptyFunctionBody &&
|
||||
I[1]->First->is(tok::r_brace))
|
||||
return tryMergeSimpleBlock(I, E, Limit);
|
||||
|
||||
// FIXME: TheLine->Level != 0 might or might not be the right check to do.
|
||||
// If necessary, change to something smarter.
|
||||
bool MergeShortFunctions =
|
||||
@ -195,6 +229,38 @@ private:
|
||||
(Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&
|
||||
TheLine->Level != 0);
|
||||
|
||||
if (Style.CompactNamespaces) {
|
||||
if (isNamespaceDeclaration(TheLine)) {
|
||||
int i = 0;
|
||||
unsigned closingLine = TheLine->MatchingOpeningBlockLineIndex - 1;
|
||||
for (; I + 1 + i != E && isNamespaceDeclaration(I[i + 1]) &&
|
||||
closingLine == I[i + 1]->MatchingOpeningBlockLineIndex &&
|
||||
I[i + 1]->Last->TotalLength < Limit;
|
||||
i++, closingLine--) {
|
||||
// No extra indent for compacted namespaces
|
||||
IndentTracker.skipLine(*I[i + 1]);
|
||||
|
||||
Limit -= I[i + 1]->Last->TotalLength;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
if (isEndOfNamespace(TheLine, AnnotatedLines)) {
|
||||
int i = 0;
|
||||
unsigned openingLine = TheLine->MatchingOpeningBlockLineIndex - 1;
|
||||
for (; I + 1 + i != E && isEndOfNamespace(I[i + 1], AnnotatedLines) &&
|
||||
openingLine == I[i + 1]->MatchingOpeningBlockLineIndex;
|
||||
i++, openingLine--) {
|
||||
// No space between consecutive braces
|
||||
I[i + 1]->First->SpacesRequiredBefore = !I[i]->Last->is(tok::r_brace);
|
||||
|
||||
// Indent like the outer-most namespace
|
||||
IndentTracker.nextLine(*I[i + 1]);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
if (TheLine->Last->is(TT_FunctionLBrace) &&
|
||||
TheLine->First != TheLine->Last) {
|
||||
return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
|
||||
@ -215,7 +281,10 @@ private:
|
||||
Limit -= 2;
|
||||
|
||||
unsigned MergedLines = 0;
|
||||
if (MergeShortFunctions) {
|
||||
if (MergeShortFunctions ||
|
||||
(Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty &&
|
||||
I[1]->First == I[1]->Last && I + 2 != E &&
|
||||
I[2]->First->is(tok::r_brace))) {
|
||||
MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
|
||||
// If we managed to merge the block, count the function header, which is
|
||||
// on a separate line.
|
||||
@ -449,6 +518,7 @@ private:
|
||||
const SmallVectorImpl<AnnotatedLine *>::const_iterator End;
|
||||
|
||||
SmallVectorImpl<AnnotatedLine *>::const_iterator Next;
|
||||
const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines;
|
||||
};
|
||||
|
||||
static void markFinalized(FormatToken *Tok) {
|
||||
|
@ -492,6 +492,11 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
|
||||
nextToken();
|
||||
Line->Level = InitialLevel;
|
||||
Line->MatchingOpeningBlockLineIndex = OpeningLineIndex;
|
||||
if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) {
|
||||
// Update the opening line to add the forward reference as well
|
||||
(*CurrentLines)[OpeningLineIndex].MatchingOpeningBlockLineIndex =
|
||||
CurrentLines->size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isGoogScope(const UnwrappedLine &Line) {
|
||||
|
@ -43,6 +43,10 @@ public:
|
||||
|
||||
/// \brief Replaces the whitespace in front of \p Tok. Only call once for
|
||||
/// each \c AnnotatedToken.
|
||||
///
|
||||
/// \p StartOfTokenColumn is the column at which the token will start after
|
||||
/// this replacement. It is needed for determining how \p Spaces is turned
|
||||
/// into tabs and spaces for some format styles.
|
||||
void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces,
|
||||
unsigned StartOfTokenColumn,
|
||||
bool InPPDirective = false);
|
||||
|
@ -142,7 +142,7 @@ std::unique_ptr<ASTConsumer> clang::CreateASTDumper(StringRef FilterString,
|
||||
bool DumpDecls,
|
||||
bool Deserialize,
|
||||
bool DumpLookups) {
|
||||
assert((DumpDecls || DumpLookups) && "nothing to dump");
|
||||
assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
|
||||
return llvm::make_unique<ASTPrinter>(nullptr,
|
||||
Deserialize ? ASTPrinter::DumpFull :
|
||||
DumpDecls ? ASTPrinter::Dump :
|
||||
|
@ -649,8 +649,14 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
|
||||
Opts.NoUseJumpTables = Args.hasArg(OPT_fno_jump_tables);
|
||||
|
||||
Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ);
|
||||
const Arg *A = Args.getLastArg(OPT_flto, OPT_flto_EQ);
|
||||
Opts.EmitSummaryIndex = A && A->containsValue("thin");
|
||||
Opts.EmitSummaryIndex = false;
|
||||
if (Arg *A = Args.getLastArg(OPT_flto_EQ)) {
|
||||
StringRef S = A->getValue();
|
||||
if (S == "thin")
|
||||
Opts.EmitSummaryIndex = true;
|
||||
else if (S != "full")
|
||||
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << S;
|
||||
}
|
||||
Opts.LTOUnit = Args.hasFlag(OPT_flto_unit, OPT_fno_lto_unit, false);
|
||||
if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) {
|
||||
if (IK.getLanguage() != InputKind::LLVM_IR)
|
||||
|
@ -293,6 +293,12 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitDecompositionDecl(const DecompositionDecl *D) {
|
||||
for (const auto *Binding : D->bindings())
|
||||
TRY_DECL(Binding, IndexCtx.handleDecl(Binding));
|
||||
return Base::VisitDecompositionDecl(D);
|
||||
}
|
||||
|
||||
bool VisitFieldDecl(const FieldDecl *D) {
|
||||
SmallVector<SymbolRelation, 4> Relations;
|
||||
gatherTemplatePseudoOverrides(D, Relations);
|
||||
@ -682,6 +688,13 @@ public:
|
||||
bool VisitImportDecl(const ImportDecl *D) {
|
||||
return IndexCtx.importedModule(D);
|
||||
}
|
||||
|
||||
bool VisitStaticAssertDecl(const StaticAssertDecl *D) {
|
||||
IndexCtx.indexBody(D->getAssertExpr(),
|
||||
dyn_cast<NamedDecl>(D->getDeclContext()),
|
||||
D->getLexicalDeclContext());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
@ -301,6 +301,10 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
|
||||
Info.Kind = SymbolKind::TypeAlias;
|
||||
Info.Lang = SymbolLanguage::CXX;
|
||||
break;
|
||||
case Decl::Binding:
|
||||
Info.Kind = SymbolKind::Variable;
|
||||
Info.Lang = SymbolLanguage::CXX;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -44,20 +44,22 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
|
||||
// Otherwise, use the best fit.
|
||||
ClosestMatch = (*Entry)->NumUnexpArgTokens;
|
||||
}
|
||||
|
||||
|
||||
MacroArgs *Result;
|
||||
if (!ResultEnt) {
|
||||
// Allocate memory for a MacroArgs object with the lexer tokens at the end.
|
||||
Result = (MacroArgs*)malloc(sizeof(MacroArgs) +
|
||||
UnexpArgTokens.size() * sizeof(Token));
|
||||
Result = (MacroArgs *)malloc(sizeof(MacroArgs) +
|
||||
UnexpArgTokens.size() * sizeof(Token));
|
||||
// Construct the MacroArgs object.
|
||||
new (Result) MacroArgs(UnexpArgTokens.size(), VarargsElided);
|
||||
new (Result)
|
||||
MacroArgs(UnexpArgTokens.size(), VarargsElided, MI->getNumArgs());
|
||||
} else {
|
||||
Result = *ResultEnt;
|
||||
// Unlink this node from the preprocessors singly linked list.
|
||||
*ResultEnt = Result->ArgCache;
|
||||
Result->NumUnexpArgTokens = UnexpArgTokens.size();
|
||||
Result->VarargsElided = VarargsElided;
|
||||
Result->NumMacroArgs = MI->getNumArgs();
|
||||
}
|
||||
|
||||
// Copy the actual unexpanded tokens to immediately after the result ptr.
|
||||
@ -298,12 +300,10 @@ const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
|
||||
Preprocessor &PP,
|
||||
SourceLocation ExpansionLocStart,
|
||||
SourceLocation ExpansionLocEnd) {
|
||||
assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!");
|
||||
if (StringifiedArgs.empty()) {
|
||||
StringifiedArgs.resize(getNumArguments());
|
||||
memset((void*)&StringifiedArgs[0], 0,
|
||||
sizeof(StringifiedArgs[0])*getNumArguments());
|
||||
}
|
||||
assert(ArgNo < getNumMacroArguments() && "Invalid argument number!");
|
||||
if (StringifiedArgs.empty())
|
||||
StringifiedArgs.resize(getNumMacroArguments(), {});
|
||||
|
||||
if (StringifiedArgs[ArgNo].isNot(tok::string_literal))
|
||||
StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP,
|
||||
/*Charify=*/false,
|
||||
|
@ -4542,8 +4542,10 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
|
||||
bool EnteringContext) {
|
||||
if (!SS.getScopeRep() || !CodeCompleter)
|
||||
return;
|
||||
|
||||
DeclContext *Ctx = computeDeclContext(SS, EnteringContext);
|
||||
|
||||
// Always pretend to enter a context to ensure that a dependent type
|
||||
// resolves to a dependent record.
|
||||
DeclContext *Ctx = computeDeclContext(SS, /*EnteringContext=*/true);
|
||||
if (!Ctx)
|
||||
return;
|
||||
|
||||
@ -4573,7 +4575,9 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
|
||||
Results.ExitScope();
|
||||
|
||||
CodeCompletionDeclConsumer Consumer(Results, CurContext);
|
||||
LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer);
|
||||
LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer,
|
||||
/*IncludeGlobalScope=*/true,
|
||||
/*IncludeDependentBases=*/true);
|
||||
|
||||
HandleCodeCompleteResults(this, CodeCompleter,
|
||||
Results.getCompletionContext(),
|
||||
|
@ -470,11 +470,11 @@ static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc,
|
||||
return ScopeInfo;
|
||||
}
|
||||
|
||||
static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc,
|
||||
StringRef Keyword) {
|
||||
if (!checkCoroutineContext(S, KWLoc, Keyword))
|
||||
bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
|
||||
StringRef Keyword) {
|
||||
if (!checkCoroutineContext(*this, KWLoc, Keyword))
|
||||
return false;
|
||||
auto *ScopeInfo = S.getCurFunction();
|
||||
auto *ScopeInfo = getCurFunction();
|
||||
assert(ScopeInfo->CoroutinePromise);
|
||||
|
||||
// If we have existing coroutine statements then we have already built
|
||||
@ -484,24 +484,24 @@ static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc,
|
||||
|
||||
ScopeInfo->setNeedsCoroutineSuspends(false);
|
||||
|
||||
auto *Fn = cast<FunctionDecl>(S.CurContext);
|
||||
auto *Fn = cast<FunctionDecl>(CurContext);
|
||||
SourceLocation Loc = Fn->getLocation();
|
||||
// Build the initial suspend point
|
||||
auto buildSuspends = [&](StringRef Name) mutable -> StmtResult {
|
||||
ExprResult Suspend =
|
||||
buildPromiseCall(S, ScopeInfo->CoroutinePromise, Loc, Name, None);
|
||||
buildPromiseCall(*this, ScopeInfo->CoroutinePromise, Loc, Name, None);
|
||||
if (Suspend.isInvalid())
|
||||
return StmtError();
|
||||
Suspend = buildOperatorCoawaitCall(S, SC, Loc, Suspend.get());
|
||||
Suspend = buildOperatorCoawaitCall(*this, SC, Loc, Suspend.get());
|
||||
if (Suspend.isInvalid())
|
||||
return StmtError();
|
||||
Suspend = S.BuildResolvedCoawaitExpr(Loc, Suspend.get(),
|
||||
/*IsImplicit*/ true);
|
||||
Suspend = S.ActOnFinishFullExpr(Suspend.get());
|
||||
Suspend = BuildResolvedCoawaitExpr(Loc, Suspend.get(),
|
||||
/*IsImplicit*/ true);
|
||||
Suspend = ActOnFinishFullExpr(Suspend.get());
|
||||
if (Suspend.isInvalid()) {
|
||||
S.Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required)
|
||||
Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required)
|
||||
<< ((Name == "initial_suspend") ? 0 : 1);
|
||||
S.Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword;
|
||||
Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword;
|
||||
return StmtError();
|
||||
}
|
||||
return cast<Stmt>(Suspend.get());
|
||||
@ -521,7 +521,7 @@ static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc,
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
|
||||
if (!actOnCoroutineBodyStart(*this, S, Loc, "co_await")) {
|
||||
if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) {
|
||||
CorrectDelayedTyposInExpr(E);
|
||||
return ExprError();
|
||||
}
|
||||
@ -613,7 +613,7 @@ ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *E,
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
|
||||
if (!actOnCoroutineBodyStart(*this, S, Loc, "co_yield")) {
|
||||
if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) {
|
||||
CorrectDelayedTyposInExpr(E);
|
||||
return ExprError();
|
||||
}
|
||||
@ -658,14 +658,15 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
|
||||
if (RSS.IsInvalid)
|
||||
return ExprError();
|
||||
|
||||
Expr *Res = new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1],
|
||||
RSS.Results[2], RSS.OpaqueValue);
|
||||
Expr *Res =
|
||||
new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1],
|
||||
RSS.Results[2], RSS.OpaqueValue);
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
StmtResult Sema::ActOnCoreturnStmt(Scope *S, SourceLocation Loc, Expr *E) {
|
||||
if (!actOnCoroutineBodyStart(*this, S, Loc, "co_return")) {
|
||||
if (!ActOnCoroutineBodyStart(S, Loc, "co_return")) {
|
||||
CorrectDelayedTyposInExpr(E);
|
||||
return StmtError();
|
||||
}
|
||||
|
@ -313,8 +313,8 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range,
|
||||
/// \returns true if IdxExpr is a valid index.
|
||||
template <typename AttrInfo>
|
||||
static bool checkFunctionOrMethodParameterIndex(
|
||||
Sema &S, const Decl *D, const AttrInfo& Attr,
|
||||
unsigned AttrArgNum, const Expr *IdxExpr, uint64_t &Idx) {
|
||||
Sema &S, const Decl *D, const AttrInfo &Attr, unsigned AttrArgNum,
|
||||
const Expr *IdxExpr, uint64_t &Idx, bool AllowImplicitThis = false) {
|
||||
assert(isFunctionOrMethodOrBlock(D));
|
||||
|
||||
// In C++ the implicit 'this' function parameter also counts.
|
||||
@ -341,7 +341,7 @@ static bool checkFunctionOrMethodParameterIndex(
|
||||
return false;
|
||||
}
|
||||
Idx--; // Convert to zero-based.
|
||||
if (HasImplicitThisParam) {
|
||||
if (HasImplicitThisParam && !AllowImplicitThis) {
|
||||
if (Idx == 0) {
|
||||
S.Diag(getAttrLoc(Attr),
|
||||
diag::err_attribute_invalid_implicit_this_argument)
|
||||
@ -4604,14 +4604,16 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
|
||||
static void handleXRayLogArgsAttr(Sema &S, Decl *D,
|
||||
const AttributeList &Attr) {
|
||||
uint64_t ArgCount;
|
||||
|
||||
if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, Attr.getArgAsExpr(0),
|
||||
ArgCount))
|
||||
ArgCount,
|
||||
true /* AllowImplicitThis*/))
|
||||
return;
|
||||
|
||||
// ArgCount isn't a parameter index [0;n), it's a count [1;n] - hence + 1.
|
||||
D->addAttr(::new (S.Context)
|
||||
XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount,
|
||||
Attr.getAttributeSpellingListIndex()));
|
||||
XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount,
|
||||
Attr.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -12057,11 +12057,17 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
|
||||
}
|
||||
break;
|
||||
case UO_Extension:
|
||||
case UO_Coawait:
|
||||
resultType = Input.get()->getType();
|
||||
VK = Input.get()->getValueKind();
|
||||
OK = Input.get()->getObjectKind();
|
||||
break;
|
||||
case UO_Coawait:
|
||||
// It's unnessesary to represent the pass-through operator co_await in the
|
||||
// AST; just return the input expression instead.
|
||||
assert(!Input.get()->getType()->isDependentType() &&
|
||||
"the co_await expression must be non-dependant before "
|
||||
"building operator co_await");
|
||||
return Input;
|
||||
}
|
||||
if (resultType.isNull() || Input.isInvalid())
|
||||
return ExprError();
|
||||
|
@ -189,12 +189,15 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
|
||||
// have one) and, if that fails to find a match, in the scope (if
|
||||
// we're allowed to look there).
|
||||
Found.clear();
|
||||
if (Step == 0 && LookupCtx)
|
||||
if (Step == 0 && LookupCtx) {
|
||||
if (RequireCompleteDeclContext(SS, LookupCtx))
|
||||
return nullptr;
|
||||
LookupQualifiedName(Found, LookupCtx);
|
||||
else if (Step == 1 && LookInScope && S)
|
||||
} else if (Step == 1 && LookInScope && S) {
|
||||
LookupName(Found, S);
|
||||
else
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME: Should we be suppressing ambiguities here?
|
||||
if (Found.isAmbiguous())
|
||||
|
@ -1492,6 +1492,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
|
||||
bool ExplicitResultType;
|
||||
CleanupInfo LambdaCleanup;
|
||||
bool ContainsUnexpandedParameterPack;
|
||||
bool IsGenericLambda;
|
||||
{
|
||||
CallOperator = LSI->CallOperator;
|
||||
Class = LSI->Lambda;
|
||||
@ -1500,7 +1501,8 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
|
||||
ExplicitResultType = !LSI->HasImplicitReturnType;
|
||||
LambdaCleanup = LSI->Cleanup;
|
||||
ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
|
||||
|
||||
IsGenericLambda = Class->isGenericLambda();
|
||||
|
||||
CallOperator->setLexicalDeclContext(Class);
|
||||
Decl *TemplateOrNonTemplateCallOperatorDecl =
|
||||
CallOperator->getDescribedFunctionTemplate()
|
||||
@ -1520,8 +1522,13 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
|
||||
bool IsImplicit = I >= LSI->NumExplicitCaptures;
|
||||
|
||||
// Warn about unused explicit captures.
|
||||
if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed())
|
||||
DiagnoseUnusedLambdaCapture(From);
|
||||
if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
|
||||
// Initialized captures that are non-ODR used may not be eliminated.
|
||||
bool NonODRUsedInitCapture =
|
||||
IsGenericLambda && From.isNonODRUsed() && From.getInitExpr();
|
||||
if (!NonODRUsedInitCapture)
|
||||
DiagnoseUnusedLambdaCapture(From);
|
||||
}
|
||||
|
||||
// Handle 'this' capture.
|
||||
if (From.isThisCapture()) {
|
||||
@ -1568,8 +1575,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
|
||||
// same parameter and return types as the closure type's function call
|
||||
// operator.
|
||||
// FIXME: Fix generic lambda to block conversions.
|
||||
if (getLangOpts().Blocks && getLangOpts().ObjC1 &&
|
||||
!Class->isGenericLambda())
|
||||
if (getLangOpts().Blocks && getLangOpts().ObjC1 && !IsGenericLambda)
|
||||
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
|
||||
|
||||
// Finalize the lambda class.
|
||||
|
@ -1989,11 +1989,11 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
|
||||
return StmtError();
|
||||
}
|
||||
|
||||
// Coroutines: 'for co_await' implicitly co_awaits its range.
|
||||
if (CoawaitLoc.isValid()) {
|
||||
ExprResult Coawait = ActOnCoawaitExpr(S, CoawaitLoc, Range);
|
||||
if (Coawait.isInvalid()) return StmtError();
|
||||
Range = Coawait.get();
|
||||
// Build the coroutine state immediately and not later during template
|
||||
// instantiation
|
||||
if (!CoawaitLoc.isInvalid()) {
|
||||
if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await"))
|
||||
return StmtError();
|
||||
}
|
||||
|
||||
// Build auto && __range = range-init
|
||||
@ -2031,16 +2031,12 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
|
||||
/// BeginExpr and EndExpr are set and FRS_Success is returned on success;
|
||||
/// CandidateSet and BEF are set and some non-success value is returned on
|
||||
/// failure.
|
||||
static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef,
|
||||
Expr *BeginRange, Expr *EndRange,
|
||||
QualType RangeType,
|
||||
VarDecl *BeginVar,
|
||||
VarDecl *EndVar,
|
||||
SourceLocation ColonLoc,
|
||||
OverloadCandidateSet *CandidateSet,
|
||||
ExprResult *BeginExpr,
|
||||
ExprResult *EndExpr,
|
||||
BeginEndFunction *BEF) {
|
||||
static Sema::ForRangeStatus
|
||||
BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange,
|
||||
QualType RangeType, VarDecl *BeginVar, VarDecl *EndVar,
|
||||
SourceLocation ColonLoc, SourceLocation CoawaitLoc,
|
||||
OverloadCandidateSet *CandidateSet, ExprResult *BeginExpr,
|
||||
ExprResult *EndExpr, BeginEndFunction *BEF) {
|
||||
DeclarationNameInfo BeginNameInfo(
|
||||
&SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc);
|
||||
DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"),
|
||||
@ -2087,6 +2083,15 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef,
|
||||
<< ColonLoc << BEF_begin << BeginRange->getType();
|
||||
return RangeStatus;
|
||||
}
|
||||
if (!CoawaitLoc.isInvalid()) {
|
||||
// FIXME: getCurScope() should not be used during template instantiation.
|
||||
// We should pick up the set of unqualified lookup results for operator
|
||||
// co_await during the initial parse.
|
||||
*BeginExpr = SemaRef.ActOnCoawaitExpr(SemaRef.getCurScope(), ColonLoc,
|
||||
BeginExpr->get());
|
||||
if (BeginExpr->isInvalid())
|
||||
return Sema::FRS_DiagnosticIssued;
|
||||
}
|
||||
if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc,
|
||||
diag::err_for_range_iter_deduction_failure)) {
|
||||
NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF);
|
||||
@ -2206,8 +2211,12 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
||||
|
||||
// Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
|
||||
// them in properly when we instantiate the loop.
|
||||
if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check)
|
||||
if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) {
|
||||
if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar))
|
||||
for (auto *Binding : DD->bindings())
|
||||
Binding->setType(Context.DependentTy);
|
||||
LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
|
||||
}
|
||||
} else if (!BeginDeclStmt.get()) {
|
||||
SourceLocation RangeLoc = RangeVar->getLocation();
|
||||
|
||||
@ -2249,6 +2258,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
||||
|
||||
// begin-expr is __range.
|
||||
BeginExpr = BeginRangeRef;
|
||||
if (!CoawaitLoc.isInvalid()) {
|
||||
BeginExpr = ActOnCoawaitExpr(S, ColonLoc, BeginExpr.get());
|
||||
if (BeginExpr.isInvalid())
|
||||
return StmtError();
|
||||
}
|
||||
if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc,
|
||||
diag::err_for_range_iter_deduction_failure)) {
|
||||
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
||||
@ -2331,11 +2345,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
||||
OverloadCandidateSet CandidateSet(RangeLoc,
|
||||
OverloadCandidateSet::CSK_Normal);
|
||||
BeginEndFunction BEFFailure;
|
||||
ForRangeStatus RangeStatus =
|
||||
BuildNonArrayForRange(*this, BeginRangeRef.get(),
|
||||
EndRangeRef.get(), RangeType,
|
||||
BeginVar, EndVar, ColonLoc, &CandidateSet,
|
||||
&BeginExpr, &EndExpr, &BEFFailure);
|
||||
ForRangeStatus RangeStatus = BuildNonArrayForRange(
|
||||
*this, BeginRangeRef.get(), EndRangeRef.get(), RangeType, BeginVar,
|
||||
EndVar, ColonLoc, CoawaitLoc, &CandidateSet, &BeginExpr, &EndExpr,
|
||||
&BEFFailure);
|
||||
|
||||
if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction &&
|
||||
BEFFailure == BEF_begin) {
|
||||
@ -2432,6 +2445,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
||||
|
||||
IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
|
||||
if (!IncrExpr.isInvalid() && CoawaitLoc.isValid())
|
||||
// FIXME: getCurScope() should not be used during template instantiation.
|
||||
// We should pick up the set of unqualified lookup results for operator
|
||||
// co_await during the initial parse.
|
||||
IncrExpr = ActOnCoawaitExpr(S, CoawaitLoc, IncrExpr.get());
|
||||
if (!IncrExpr.isInvalid())
|
||||
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
|
||||
|
@ -9242,6 +9242,7 @@ void ASTReader::diagnoseOdrViolations() {
|
||||
|
||||
// Used with err_module_odr_violation_mismatch_decl and
|
||||
// note_module_odr_violation_mismatch_decl
|
||||
// This list should be the same Decl's as in ODRHash::isWhiteListedDecl
|
||||
enum {
|
||||
EndOfClass,
|
||||
PublicSpecifer,
|
||||
@ -9250,6 +9251,9 @@ void ASTReader::diagnoseOdrViolations() {
|
||||
StaticAssert,
|
||||
Field,
|
||||
CXXMethod,
|
||||
TypeAlias,
|
||||
TypeDef,
|
||||
Var,
|
||||
Other
|
||||
} FirstDiffType = Other,
|
||||
SecondDiffType = Other;
|
||||
@ -9277,6 +9281,12 @@ void ASTReader::diagnoseOdrViolations() {
|
||||
return Field;
|
||||
case Decl::CXXMethod:
|
||||
return CXXMethod;
|
||||
case Decl::TypeAlias:
|
||||
return TypeAlias;
|
||||
case Decl::Typedef:
|
||||
return TypeDef;
|
||||
case Decl::Var:
|
||||
return Var;
|
||||
}
|
||||
};
|
||||
|
||||
@ -9373,6 +9383,15 @@ void ASTReader::diagnoseOdrViolations() {
|
||||
MethodNumberParameters,
|
||||
MethodParameterType,
|
||||
MethodParameterName,
|
||||
MethodParameterSingleDefaultArgument,
|
||||
MethodParameterDifferentDefaultArgument,
|
||||
TypedefName,
|
||||
TypedefType,
|
||||
VarName,
|
||||
VarType,
|
||||
VarSingleInitializer,
|
||||
VarDifferentInitializer,
|
||||
VarConstexpr,
|
||||
};
|
||||
|
||||
// These lambdas have the common portions of the ODR diagnostics. This
|
||||
@ -9739,6 +9758,38 @@ void ASTReader::diagnoseOdrViolations() {
|
||||
ParameterMismatch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const Expr *FirstInit = FirstParam->getInit();
|
||||
const Expr *SecondInit = SecondParam->getInit();
|
||||
if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
|
||||
ODRDiagError(FirstMethod->getLocation(),
|
||||
FirstMethod->getSourceRange(),
|
||||
MethodParameterSingleDefaultArgument)
|
||||
<< FirstName << (I + 1) << (FirstInit == nullptr)
|
||||
<< (FirstInit ? FirstInit->getSourceRange() : SourceRange());
|
||||
ODRDiagNote(SecondMethod->getLocation(),
|
||||
SecondMethod->getSourceRange(),
|
||||
MethodParameterSingleDefaultArgument)
|
||||
<< SecondName << (I + 1) << (SecondInit == nullptr)
|
||||
<< (SecondInit ? SecondInit->getSourceRange() : SourceRange());
|
||||
ParameterMismatch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FirstInit && SecondInit &&
|
||||
ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
|
||||
ODRDiagError(FirstMethod->getLocation(),
|
||||
FirstMethod->getSourceRange(),
|
||||
MethodParameterDifferentDefaultArgument)
|
||||
<< FirstName << (I + 1) << FirstInit->getSourceRange();
|
||||
ODRDiagNote(SecondMethod->getLocation(),
|
||||
SecondMethod->getSourceRange(),
|
||||
MethodParameterDifferentDefaultArgument)
|
||||
<< SecondName << (I + 1) << SecondInit->getSourceRange();
|
||||
ParameterMismatch = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (ParameterMismatch) {
|
||||
@ -9748,6 +9799,109 @@ void ASTReader::diagnoseOdrViolations() {
|
||||
|
||||
break;
|
||||
}
|
||||
case TypeAlias:
|
||||
case TypeDef: {
|
||||
TypedefNameDecl *FirstTD = cast<TypedefNameDecl>(FirstDecl);
|
||||
TypedefNameDecl *SecondTD = cast<TypedefNameDecl>(SecondDecl);
|
||||
auto FirstName = FirstTD->getDeclName();
|
||||
auto SecondName = SecondTD->getDeclName();
|
||||
if (FirstName != SecondName) {
|
||||
ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(),
|
||||
TypedefName)
|
||||
<< (FirstDiffType == TypeAlias) << FirstName;
|
||||
ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(),
|
||||
TypedefName)
|
||||
<< (FirstDiffType == TypeAlias) << SecondName;
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
QualType FirstType = FirstTD->getUnderlyingType();
|
||||
QualType SecondType = SecondTD->getUnderlyingType();
|
||||
if (ComputeQualTypeODRHash(FirstType) !=
|
||||
ComputeQualTypeODRHash(SecondType)) {
|
||||
ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(),
|
||||
TypedefType)
|
||||
<< (FirstDiffType == TypeAlias) << FirstName << FirstType;
|
||||
ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(),
|
||||
TypedefType)
|
||||
<< (FirstDiffType == TypeAlias) << SecondName << SecondType;
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Var: {
|
||||
VarDecl *FirstVD = cast<VarDecl>(FirstDecl);
|
||||
VarDecl *SecondVD = cast<VarDecl>(SecondDecl);
|
||||
auto FirstName = FirstVD->getDeclName();
|
||||
auto SecondName = SecondVD->getDeclName();
|
||||
if (FirstName != SecondName) {
|
||||
ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
|
||||
VarName)
|
||||
<< FirstName;
|
||||
ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
|
||||
VarName)
|
||||
<< SecondName;
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
QualType FirstType = FirstVD->getType();
|
||||
QualType SecondType = SecondVD->getType();
|
||||
if (ComputeQualTypeODRHash(FirstType) !=
|
||||
ComputeQualTypeODRHash(SecondType)) {
|
||||
ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
|
||||
VarType)
|
||||
<< FirstName << FirstType;
|
||||
ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
|
||||
VarType)
|
||||
<< SecondName << SecondType;
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const Expr *FirstInit = FirstVD->getInit();
|
||||
const Expr *SecondInit = SecondVD->getInit();
|
||||
if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
|
||||
ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
|
||||
VarSingleInitializer)
|
||||
<< FirstName << (FirstInit == nullptr)
|
||||
<< (FirstInit ? FirstInit->getSourceRange(): SourceRange());
|
||||
ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
|
||||
VarSingleInitializer)
|
||||
<< SecondName << (SecondInit == nullptr)
|
||||
<< (SecondInit ? SecondInit->getSourceRange() : SourceRange());
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FirstInit && SecondInit &&
|
||||
ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
|
||||
ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
|
||||
VarDifferentInitializer)
|
||||
<< FirstName << FirstInit->getSourceRange();
|
||||
ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
|
||||
VarDifferentInitializer)
|
||||
<< SecondName << SecondInit->getSourceRange();
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const bool FirstIsConstexpr = FirstVD->isConstexpr();
|
||||
const bool SecondIsConstexpr = SecondVD->isConstexpr();
|
||||
if (FirstIsConstexpr != SecondIsConstexpr) {
|
||||
ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
|
||||
VarConstexpr)
|
||||
<< FirstName << FirstIsConstexpr;
|
||||
ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
|
||||
VarConstexpr)
|
||||
<< SecondName << SecondIsConstexpr;
|
||||
Diagnosed = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Diagnosed == true)
|
||||
|
@ -216,30 +216,6 @@ namespace clang {
|
||||
TypedefNameForLinkage(nullptr), HasPendingBody(false),
|
||||
IsDeclMarkedUsed(false) {}
|
||||
|
||||
template <typename T> static
|
||||
void AddLazySpecializations(T *D,
|
||||
SmallVectorImpl<serialization::DeclID>& IDs) {
|
||||
if (IDs.empty())
|
||||
return;
|
||||
|
||||
// FIXME: We should avoid this pattern of getting the ASTContext.
|
||||
ASTContext &C = D->getASTContext();
|
||||
|
||||
auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations;
|
||||
|
||||
if (auto &Old = LazySpecializations) {
|
||||
IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]);
|
||||
std::sort(IDs.begin(), IDs.end());
|
||||
IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
|
||||
}
|
||||
|
||||
auto *Result = new (C) serialization::DeclID[1 + IDs.size()];
|
||||
*Result = IDs.size();
|
||||
std::copy(IDs.begin(), IDs.end(), Result + 1);
|
||||
|
||||
LazySpecializations = Result;
|
||||
}
|
||||
|
||||
template <typename DeclT>
|
||||
static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D);
|
||||
static Decl *getMostRecentDeclImpl(...);
|
||||
@ -268,7 +244,7 @@ namespace clang {
|
||||
void ReadFunctionDefinition(FunctionDecl *FD);
|
||||
void Visit(Decl *D);
|
||||
|
||||
void UpdateDecl(Decl *D, llvm::SmallVectorImpl<serialization::DeclID>&);
|
||||
void UpdateDecl(Decl *D);
|
||||
|
||||
static void setNextObjCCategory(ObjCCategoryDecl *Cat,
|
||||
ObjCCategoryDecl *Next) {
|
||||
@ -1976,6 +1952,21 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
|
||||
return Redecl;
|
||||
}
|
||||
|
||||
static DeclID *newDeclIDList(ASTContext &Context, DeclID *Old,
|
||||
SmallVectorImpl<DeclID> &IDs) {
|
||||
assert(!IDs.empty() && "no IDs to add to list");
|
||||
if (Old) {
|
||||
IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]);
|
||||
std::sort(IDs.begin(), IDs.end());
|
||||
IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
|
||||
}
|
||||
|
||||
auto *Result = new (Context) DeclID[1 + IDs.size()];
|
||||
*Result = IDs.size();
|
||||
std::copy(IDs.begin(), IDs.end(), Result + 1);
|
||||
return Result;
|
||||
}
|
||||
|
||||
void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
||||
RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
|
||||
|
||||
@ -1984,7 +1975,12 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
||||
// the specializations.
|
||||
SmallVector<serialization::DeclID, 32> SpecIDs;
|
||||
ReadDeclIDList(SpecIDs);
|
||||
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
|
||||
|
||||
if (!SpecIDs.empty()) {
|
||||
auto *CommonPtr = D->getCommonPtr();
|
||||
CommonPtr->LazySpecializations = newDeclIDList(
|
||||
Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
|
||||
}
|
||||
}
|
||||
|
||||
if (D->getTemplatedDecl()->TemplateOrInstantiation) {
|
||||
@ -2011,7 +2007,12 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
|
||||
// the specializations.
|
||||
SmallVector<serialization::DeclID, 32> SpecIDs;
|
||||
ReadDeclIDList(SpecIDs);
|
||||
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
|
||||
|
||||
if (!SpecIDs.empty()) {
|
||||
auto *CommonPtr = D->getCommonPtr();
|
||||
CommonPtr->LazySpecializations = newDeclIDList(
|
||||
Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2117,7 +2118,12 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
|
||||
// This FunctionTemplateDecl owns a CommonPtr; read it.
|
||||
SmallVector<serialization::DeclID, 32> SpecIDs;
|
||||
ReadDeclIDList(SpecIDs);
|
||||
ASTDeclReader::AddLazySpecializations(D, SpecIDs);
|
||||
|
||||
if (!SpecIDs.empty()) {
|
||||
auto *CommonPtr = D->getCommonPtr();
|
||||
CommonPtr->LazySpecializations = newDeclIDList(
|
||||
Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3661,9 +3667,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
|
||||
Decl *D = Record.D;
|
||||
ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
|
||||
DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);
|
||||
|
||||
llvm::SmallVector<serialization::DeclID, 8> PendingLazySpecializationIDs;
|
||||
|
||||
if (UpdI != DeclUpdateOffsets.end()) {
|
||||
auto UpdateOffsets = std::move(UpdI->second);
|
||||
DeclUpdateOffsets.erase(UpdI);
|
||||
@ -3688,7 +3691,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
|
||||
|
||||
ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID,
|
||||
SourceLocation());
|
||||
Reader.UpdateDecl(D, PendingLazySpecializationIDs);
|
||||
Reader.UpdateDecl(D);
|
||||
|
||||
// We might have made this declaration interesting. If so, remember that
|
||||
// we need to hand it off to the consumer.
|
||||
@ -3700,17 +3703,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add the lazy specializations to the template.
|
||||
assert((PendingLazySpecializationIDs.empty() || isa<ClassTemplateDecl>(D) ||
|
||||
isa<FunctionTemplateDecl>(D) || isa<VarTemplateDecl>(D)) &&
|
||||
"Must not have pending specializations");
|
||||
if (auto *CTD = dyn_cast<ClassTemplateDecl>(D))
|
||||
ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs);
|
||||
else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
|
||||
ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs);
|
||||
else if (auto *VTD = dyn_cast<VarTemplateDecl>(D))
|
||||
ASTDeclReader::AddLazySpecializations(VTD, PendingLazySpecializationIDs);
|
||||
PendingLazySpecializationIDs.clear();
|
||||
|
||||
// Load the pending visible updates for this decl context, if it has any.
|
||||
auto I = PendingVisibleUpdates.find(ID);
|
||||
@ -3907,8 +3899,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) {
|
||||
}
|
||||
}
|
||||
|
||||
void ASTDeclReader::UpdateDecl(Decl *D,
|
||||
llvm::SmallVectorImpl<serialization::DeclID> &PendingLazySpecializationIDs) {
|
||||
void ASTDeclReader::UpdateDecl(Decl *D) {
|
||||
while (Record.getIdx() < Record.size()) {
|
||||
switch ((DeclUpdateKind)Record.readInt()) {
|
||||
case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
|
||||
@ -3924,8 +3915,8 @@ void ASTDeclReader::UpdateDecl(Decl *D,
|
||||
}
|
||||
|
||||
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
|
||||
// It will be added to the template's lazy specialization set.
|
||||
PendingLazySpecializationIDs.push_back(ReadDeclID());
|
||||
// It will be added to the template's specializations set when loaded.
|
||||
(void)Record.readDecl();
|
||||
break;
|
||||
|
||||
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
|
||||
|
@ -957,6 +957,12 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
|
||||
return RuntimeDefinition();
|
||||
|
||||
DynamicTypeInfo DTI = getDynamicTypeInfo(getState(), Receiver);
|
||||
if (!DTI.isValid()) {
|
||||
assert(isa<AllocaRegion>(Receiver) &&
|
||||
"Unhandled untyped region class!");
|
||||
return RuntimeDefinition();
|
||||
}
|
||||
|
||||
QualType DynType = DTI.getType();
|
||||
CanBeSubClassed = DTI.canBeASubClass();
|
||||
ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType.getCanonicalType());
|
||||
|
@ -4,6 +4,9 @@
|
||||
# error Compiler does not support Objective-C generics?
|
||||
#endif
|
||||
|
||||
typedef __typeof(sizeof(int)) size_t;
|
||||
void *memset(void *, int, size_t);
|
||||
|
||||
#define nil 0
|
||||
typedef unsigned long NSUInteger;
|
||||
typedef int BOOL;
|
||||
@ -21,6 +24,7 @@ __attribute__((objc_root_class))
|
||||
@end
|
||||
|
||||
@interface NSArray<ObjectType> : NSObject
|
||||
- (void) init;
|
||||
- (BOOL)contains:(ObjectType)obj;
|
||||
- (ObjectType)getObjAtIndex:(NSUInteger)idx;
|
||||
- (ObjectType)objectAtIndexedSubscript:(NSUInteger)idx;
|
||||
@ -55,3 +59,11 @@ void testArgument(NSArray<MyType *> *arr, id element) {
|
||||
// MyType!
|
||||
[element myFunction:0 myParam:0 ];
|
||||
}
|
||||
|
||||
// Do not try this at home! The analyzer shouldn't crash though when it
|
||||
// tries to figure out the dynamic type behind the alloca's return value.
|
||||
void testAlloca(size_t NSArrayClassSizeWeKnowSomehow) {
|
||||
NSArray *arr = __builtin_alloca(NSArrayClassSizeWeKnowSomehow);
|
||||
memset(arr, 0, NSArrayClassSizeWeKnowSomehow);
|
||||
[arr init]; // no-crash
|
||||
}
|
||||
|
@ -5,24 +5,39 @@ import lit.TestRunner
|
||||
class AnalyzerTest(lit.formats.ShTest):
|
||||
|
||||
def execute(self, test, litConfig):
|
||||
result = self.executeWithAnalyzeSubstitution(
|
||||
test, litConfig, '-analyzer-constraints=range')
|
||||
results = []
|
||||
|
||||
if result.code == lit.Test.FAIL:
|
||||
return result
|
||||
# Parse any test requirements ('REQUIRES: ')
|
||||
saved_test = test
|
||||
lit.TestRunner.parseIntegratedTestScript(test)
|
||||
|
||||
if 'z3' not in test.requires:
|
||||
results.append(self.executeWithAnalyzeSubstitution(
|
||||
saved_test, litConfig, '-analyzer-constraints=range'))
|
||||
|
||||
if results[-1].code == lit.Test.FAIL:
|
||||
return results[-1]
|
||||
|
||||
# If z3 backend available, add an additional run line for it
|
||||
if test.config.clang_staticanalyzer_z3 == '1':
|
||||
result = self.executeWithAnalyzeSubstitution(
|
||||
test, litConfig, '-analyzer-constraints=z3 -DANALYZER_CM_Z3')
|
||||
results.append(self.executeWithAnalyzeSubstitution(
|
||||
saved_test, litConfig, '-analyzer-constraints=z3 -DANALYZER_CM_Z3'))
|
||||
|
||||
return result
|
||||
# Combine all result outputs into the last element
|
||||
for x in results:
|
||||
if x != results[-1]:
|
||||
results[-1].output = x.output + results[-1].output
|
||||
|
||||
if results:
|
||||
return results[-1]
|
||||
return lit.Test.Result(lit.Test.UNSUPPORTED,
|
||||
"Test requires the following unavailable features: z3")
|
||||
|
||||
def executeWithAnalyzeSubstitution(self, test, litConfig, substitution):
|
||||
saved_substitutions = list(test.config.substitutions)
|
||||
test.config.substitutions.append(('%analyze', substitution))
|
||||
result = lit.TestRunner.executeShTest(test, litConfig,
|
||||
self.execute_external)
|
||||
self.execute_external)
|
||||
test.config.substitutions = saved_substitutions
|
||||
|
||||
return result
|
||||
|
@ -145,4 +145,22 @@ public:
|
||||
// CHECK-CC6: o2 : [#BaseTemplate<T>#]o2
|
||||
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:142:11 %s -o - | FileCheck -check-prefix=CHECK-CC6 %s
|
||||
}
|
||||
|
||||
static void staticFn(T &obj);
|
||||
|
||||
struct Nested { };
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void dependentColonColonCompletion() {
|
||||
Template<T>::staticFn();
|
||||
// CHECK-CC7: function : [#void#]function()
|
||||
// CHECK-CC7: Nested : Nested
|
||||
// CHECK-CC7: o1 : [#BaseTemplate<int>#]o1
|
||||
// CHECK-CC7: o2 : [#BaseTemplate<T>#]o2
|
||||
// CHECK-CC7: staticFn : [#void#]staticFn(<#T &obj#>)
|
||||
// CHECK-CC7: Template : Template
|
||||
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:156:16 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
|
||||
typename Template<T>::Nested m;
|
||||
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:164:25 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
|
||||
}
|
||||
|
9
test/CodeGen/Inputs/thinlto-multi-module.ll
Normal file
9
test/CodeGen/Inputs/thinlto-multi-module.ll
Normal file
@ -0,0 +1,9 @@
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
define void @f2() {
|
||||
ret void
|
||||
}
|
||||
|
||||
!0 = !{i32 1, !"ThinLTO", i32 0}
|
||||
!llvm.module.flags = !{ !0 }
|
@ -56,6 +56,13 @@ void t4() {}
|
||||
void t7() __attribute__((noreturn, nothrow));
|
||||
void t7() { while (1) {} }
|
||||
|
||||
// CHECK: define void @t72() [[COLDDEF:#[0-9]+]] {
|
||||
void t71(void) __attribute__((cold));
|
||||
void t72() __attribute__((cold));
|
||||
void t72() { t71(); }
|
||||
// CHECK: call void @t71() [[COLDSITE:#[0-9]+]]
|
||||
// CHECK: declare void @t71() [[COLDDECL:#[0-9]+]]
|
||||
|
||||
// CHECK: define void @t10() [[NUW]] section "SECT" {
|
||||
void t10(void) __attribute__((section("SECT")));
|
||||
void t10(void) {}
|
||||
@ -92,3 +99,6 @@ void __attribute__((section(".bar"))) t22(void) {}
|
||||
|
||||
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }
|
||||
// CHECK: attributes [[NR]] = { noinline noreturn nounwind{{.*}} }
|
||||
// CHECK: attributes [[COLDDEF]] = { cold {{.*}}}
|
||||
// CHECK: attributes [[COLDDECL]] = { cold {{.*}}}
|
||||
// CHECK: attributes [[COLDSITE]] = { cold {{.*}}}
|
||||
|
@ -1427,3 +1427,51 @@ float test_mm256_cvtss_f32(__m256 __a)
|
||||
// CHECK: extractelement <8 x float> %{{.*}}, i32 0
|
||||
return _mm256_cvtss_f32(__a);
|
||||
}
|
||||
|
||||
__m256 test_mm256_cmp_ps_true(__m256 a, __m256 b) {
|
||||
// CHECK-LABEL: @test_mm256_cmp_ps_true
|
||||
// CHECK: store <8 x float> <float 0xFFFFFFFFE0000000,
|
||||
return _mm256_cmp_ps(a, b, _CMP_TRUE_UQ);
|
||||
}
|
||||
|
||||
__m256 test_mm256_cmp_pd_true(__m256 a, __m256 b) {
|
||||
// CHECK-LABEL: @test_mm256_cmp_pd_true
|
||||
// CHECK: store <4 x double> <double 0xFFFFFFFFFFFFFFFF,
|
||||
return _mm256_cmp_pd(a, b, _CMP_TRUE_UQ);
|
||||
}
|
||||
|
||||
__m256 test_mm256_cmp_ps_false(__m256 a, __m256 b) {
|
||||
// CHECK-LABEL: @test_mm256_cmp_ps_false
|
||||
// CHECK: store <8 x float> zeroinitializer, <8 x float>* %tmp, align 32
|
||||
return _mm256_cmp_ps(a, b, _CMP_FALSE_OQ);
|
||||
}
|
||||
|
||||
__m256 test_mm256_cmp_pd_false(__m256 a, __m256 b) {
|
||||
// CHECK-LABEL: @test_mm256_cmp_pd_false
|
||||
// CHECK: store <4 x double> zeroinitializer, <4 x double>* %tmp, align 32
|
||||
return _mm256_cmp_pd(a, b, _CMP_FALSE_OQ);
|
||||
}
|
||||
|
||||
__m256 test_mm256_cmp_ps_strue(__m256 a, __m256 b) {
|
||||
// CHECK-LABEL: @test_mm256_cmp_ps_strue
|
||||
// CHECK: store <8 x float> <float 0xFFFFFFFFE0000000,
|
||||
return _mm256_cmp_ps(a, b, _CMP_TRUE_US);
|
||||
}
|
||||
|
||||
__m256 test_mm256_cmp_pd_strue(__m256 a, __m256 b) {
|
||||
// CHECK-LABEL: @test_mm256_cmp_pd_strue
|
||||
// CHECK: store <4 x double> <double 0xFFFFFFFFFFFFFFFF,
|
||||
return _mm256_cmp_pd(a, b, _CMP_TRUE_US);
|
||||
}
|
||||
|
||||
__m256 test_mm256_cmp_ps_sfalse(__m256 a, __m256 b) {
|
||||
// CHECK-LABEL: @test_mm256_cmp_ps_sfalse
|
||||
// CHECK: store <8 x float> zeroinitializer, <8 x float>* %tmp, align 32
|
||||
return _mm256_cmp_ps(a, b, _CMP_FALSE_OS);
|
||||
}
|
||||
|
||||
__m256 test_mm256_cmp_pd_sfalse(__m256 a, __m256 b) {
|
||||
// CHECK-LABEL: @test_mm256_cmp_pd_sfalse
|
||||
// CHECK: store <4 x double> zeroinitializer, <4 x double>* %tmp, align 32
|
||||
return _mm256_cmp_pd(a, b, _CMP_FALSE_OS);
|
||||
}
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <altivec.h>
|
||||
|
||||
extern vector signed int vsi;
|
||||
extern vector signed int vui;
|
||||
extern vector float vf;
|
||||
extern vector unsigned char vuc;
|
||||
|
||||
void testInsertWord(void) {
|
||||
@ -34,3 +36,34 @@ void testXXSLDWI(int index) {
|
||||
vec_xxsldwi(1, 2, 3); //expected-error {{first two arguments to '__builtin_vsx_xxsldwi' must be vectors}}
|
||||
vec_xxsldwi(vsi, vuc, 2); //expected-error {{first two arguments to '__builtin_vsx_xxsldwi' must have the same type}}
|
||||
}
|
||||
|
||||
void testCTF(int index) {
|
||||
vec_ctf(vsi, index); //expected-error {{argument to '__builtin_altivec_vcfsx' must be a constant integer}}
|
||||
vec_ctf(vui, index); //expected-error {{argument to '__builtin_altivec_vcfsx' must be a constant integer}}
|
||||
}
|
||||
|
||||
void testVCFSX(int index) {
|
||||
vec_vcfsx(vsi, index); //expected-error {{argument to '__builtin_altivec_vcfsx' must be a constant integer}}
|
||||
}
|
||||
|
||||
void testVCFUX(int index) {
|
||||
vec_vcfux(vui, index); //expected-error {{argument to '__builtin_altivec_vcfux' must be a constant integer}}
|
||||
}
|
||||
|
||||
void testCTS(int index) {
|
||||
vec_cts(vf, index); //expected-error {{argument to '__builtin_altivec_vctsxs' must be a constant integer}}
|
||||
|
||||
}
|
||||
|
||||
void testVCTSXS(int index) {
|
||||
vec_vctsxs(vf, index); //expected-error {{argument to '__builtin_altivec_vctsxs' must be a constant integer}}
|
||||
}
|
||||
|
||||
void testCTU(int index) {
|
||||
vec_ctu(vf, index); //expected-error {{argument to '__builtin_altivec_vctuxs' must be a constant integer}}
|
||||
|
||||
}
|
||||
|
||||
void testVCTUXS(int index) {
|
||||
vec_vctuxs(vf, index); //expected-error {{argument to '__builtin_altivec_vctuxs' must be a constant integer}}
|
||||
}
|
||||
|
@ -3,14 +3,10 @@
|
||||
// RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple x86_64-pc-win32 -emit-llvm -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple i686-pc-linux -emit-llvm -o - | FileCheck -check-prefix LINUX %s
|
||||
|
||||
// CHECK: !llvm.module.flags = !{{{.*}}}
|
||||
// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
|
||||
// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]]}
|
||||
// CHECK: !llvm.linker.options = !{![[msvcrt:[0-9]+]]}
|
||||
// CHECK: ![[msvcrt]] = !{!"/DEFAULTLIB:msvcrt.lib"}
|
||||
|
||||
// LINUX: !llvm.module.flags = !{{{.*}}}
|
||||
// LINUX: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
|
||||
// LINUX: ![[link_opts]] = !{![[msvcrt:[0-9]+]]}
|
||||
// LINUX: !llvm.linker.options = !{![[msvcrt:[0-9]+]]}
|
||||
// LINUX: ![[msvcrt]] = !{!"-lmsvcrt"}
|
||||
|
||||
int f();
|
||||
|
@ -1,8 +1,6 @@
|
||||
// RUN: %clang_cc1 %s --linker-option=/include:foo -triple i686-pc-win32 -emit-llvm -o - | FileCheck %s
|
||||
|
||||
// CHECK: !llvm.module.flags = !{{{.*}}}
|
||||
// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
|
||||
// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]]}
|
||||
// CHECK: !llvm.linker.options = !{![[msvcrt:[0-9]+]]}
|
||||
// CHECK: ![[msvcrt]] = !{!"/include:foo"}
|
||||
|
||||
int f();
|
||||
|
17
test/CodeGen/mips-debug-info-bitfield.c
Normal file
17
test/CodeGen/mips-debug-info-bitfield.c
Normal file
@ -0,0 +1,17 @@
|
||||
// RUN: %clang_cc1 -x c -debug-info-kind=limited -triple mips-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
struct fields
|
||||
{
|
||||
unsigned a : 4;
|
||||
unsigned b : 4;
|
||||
} flags;
|
||||
|
||||
// CHECK: !DIDerivedType(tag: DW_TAG_member,
|
||||
// CHECK-SAME: {{.*}}name: "a"
|
||||
// CHECK-NOT: {{.*}}offset:
|
||||
// CHECK-SAME: {{.*}}flags: DIFlagBitField
|
||||
|
||||
// CHECK: !DIDerivedType(tag: DW_TAG_member,
|
||||
// CHECK-SAME: {{.*}}name: "b"
|
||||
// CHECK-SAME: {{.*}}offset: 4
|
||||
// CHECK-SAME: {{.*}}flags: DIFlagBitField
|
@ -14,9 +14,7 @@
|
||||
#pragma comment(linker," /bar=" BAR)
|
||||
#pragma comment(linker," /foo=\"foo bar\"")
|
||||
|
||||
// CHECK: !llvm.module.flags = !{{{.*}}}
|
||||
// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
|
||||
// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]], ![[kernel32:[0-9]+]], ![[USER32:[0-9]+]], ![[space:[0-9]+]], ![[bar:[0-9]+]], ![[foo:[0-9]+]]}
|
||||
// CHECK: !llvm.linker.options = !{![[msvcrt:[0-9]+]], ![[kernel32:[0-9]+]], ![[USER32:[0-9]+]], ![[space:[0-9]+]], ![[bar:[0-9]+]], ![[foo:[0-9]+]]}
|
||||
// CHECK: ![[msvcrt]] = !{!"/DEFAULTLIB:msvcrt.lib"}
|
||||
// CHECK: ![[kernel32]] = !{!"/DEFAULTLIB:kernel32.lib"}
|
||||
// CHECK: ![[USER32]] = !{!"/DEFAULTLIB:USER32.LIB"}
|
||||
|
@ -6,8 +6,6 @@
|
||||
#define BAR "2"
|
||||
#pragma detect_mismatch("test2", BAR)
|
||||
|
||||
// CHECK: !llvm.module.flags = !{{{.*}}}
|
||||
// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
|
||||
// CHECK: ![[link_opts]] = !{![[test:[0-9]+]], ![[test2:[0-9]+]]}
|
||||
// CHECK: !llvm.linker.options = !{![[test:[0-9]+]], ![[test2:[0-9]+]]}
|
||||
// CHECK: ![[test]] = !{!"/FAILIFMISMATCH:\22test=1\22"}
|
||||
// CHECK: ![[test2]] = !{!"/FAILIFMISMATCH:\22test2=2\22"}
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
; RUN: %clang -flto=thin -c -o %t.o %s
|
||||
; RUN: llvm-lto -thinlto -o %t %t.o
|
||||
; RUN: not %clang_cc1 -x ir %t.o -fthinlto-index=%t.thinlto.bc -backend-option -nonexistent -emit-obj -o /dev/null 2>&1 | FileCheck %s
|
||||
; RUN: not %clang_cc1 -x ir %t.o -fthinlto-index=%t.thinlto.bc -backend-option -nonexistent -emit-obj -o /dev/null 2>&1 | FileCheck %s -check-prefix=UNKNOWN
|
||||
; UNKNOWN: clang: Unknown command line argument '-nonexistent'
|
||||
|
||||
; CHECK: clang: Unknown command line argument '-nonexistent'
|
||||
; RUN: not %clang_cc1 -flto=thinfoo 2>&1 | FileCheck %s -check-prefix=INVALID
|
||||
; INVALID: error: invalid value 'thinfoo' in '-flto=thinfoo'
|
||||
|
@ -3,8 +3,8 @@
|
||||
; RUN: opt -module-summary -o %t1.o %s
|
||||
; RUN: llvm-lto -thinlto -o %t %t1.o
|
||||
|
||||
; RUN: opt -o %t2.o %S/Inputs/thinlto_backend.ll
|
||||
; RUN: llvm-cat -b -o %t1cat.o %t1.o %t2.o
|
||||
; RUN: opt -module-summary -o %t2.o %S/Inputs/thinlto-multi-module.ll
|
||||
; RUN: llvm-cat -b -o %t1cat.o %t2.o %t1.o
|
||||
; RUN: cp %t1cat.o %t1.o
|
||||
; RUN: %clang -target x86_64-unknown-linux-gnu -O2 -o %t3.o -x ir %t1.o -c -fthinlto-index=%t.thinlto.bc
|
||||
; RUN: llvm-nm %t3.o | FileCheck --check-prefix=CHECK-OBJ %s
|
||||
|
@ -5,23 +5,21 @@ void unary_arith(char *p) {
|
||||
// CHECK: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize
|
||||
// CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 1, !nosanitize
|
||||
// CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize
|
||||
// CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize
|
||||
// CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 true, i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize
|
||||
// CHECK-NEXT: [[VALID:%.*]] = and i1 true, [[DIFFVALID]], !nosanitize
|
||||
// CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize
|
||||
// CHECK-NEXT: br i1 [[POSVALID]]{{.*}}, !nosanitize
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize
|
||||
++p;
|
||||
|
||||
// CHECK: ptrtoint i8* {{.*}} to i64, !nosanitize
|
||||
// CHECK-NEXT: add i64 {{.*}}, -1, !nosanitize
|
||||
// CHECK: select i1 false{{.*}}, !nosanitize
|
||||
// CHECK-NEXT: and i1 true{{.*}}, !nosanitize
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
--p;
|
||||
|
||||
// CHECK-NOT: select
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
p++;
|
||||
|
||||
// CHECK: select
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
p--;
|
||||
}
|
||||
@ -30,22 +28,43 @@ void unary_arith(char *p) {
|
||||
void binary_arith(char *p, int i) {
|
||||
// CHECK: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %{{.*}}), !nosanitize
|
||||
// CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize
|
||||
// CHECK-NEXT: [[OFFSETOFLOW:%.*]] = or i1 false, [[SMULOFLOW]], !nosanitize
|
||||
// CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize
|
||||
// CHECK-NEXT: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize
|
||||
// CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize
|
||||
// CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize
|
||||
// CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize
|
||||
// CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize
|
||||
// CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0, !nosanitize
|
||||
// CHECK-DAG: [[OFFSETVALID:%.*]] = xor i1 [[OFFSETOFLOW]], true, !nosanitize
|
||||
// CHECK-DAG: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize
|
||||
// CHECK: [[VALID:%.*]] = and i1 [[OFFSETVALID]], [[DIFFVALID]], !nosanitize
|
||||
// CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize
|
||||
// CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize
|
||||
// CHECK: [[VALID:%.*]] = and i1 [[DIFFVALID]], [[OFFSETVALID]], !nosanitize
|
||||
// CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize
|
||||
p + i;
|
||||
|
||||
// CHECK: [[OFFSET:%.*]] = sub i64 0, {{.*}}
|
||||
// CHECK-NEXT: getelementptr inbounds {{.*}} [[OFFSET]]
|
||||
// CHECK: select
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
p - i;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @binary_arith_unsigned
|
||||
void binary_arith_unsigned(char *p, unsigned i) {
|
||||
// CHECK: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %{{.*}}), !nosanitize
|
||||
// CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize
|
||||
// CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize
|
||||
// CHECK-NEXT: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize
|
||||
// CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize
|
||||
// CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize
|
||||
// CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize
|
||||
// CHECK: [[VALID:%.*]] = and i1 [[POSVALID]], [[OFFSETVALID]], !nosanitize
|
||||
// CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize
|
||||
p + i;
|
||||
|
||||
// CHECK: [[OFFSET:%.*]] = sub i64 0, {{.*}}
|
||||
// CHECK-NEXT: getelementptr inbounds {{.*}} [[OFFSET]]
|
||||
// CHECK: select
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
p - i;
|
||||
}
|
||||
@ -55,16 +74,15 @@ void fixed_len_array(int k) {
|
||||
// CHECK: getelementptr inbounds [10 x [10 x i32]], [10 x [10 x i32]]* [[ARR:%.*]], i64 0, i64 [[IDXPROM:%.*]]
|
||||
// CHECK-NEXT: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 40, i64 [[IDXPROM]]), !nosanitize
|
||||
// CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize
|
||||
// CHECK-NEXT: [[OFFSETOFLOW:%.*]] = or i1 false, [[SMULOFLOW]], !nosanitize
|
||||
// CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize
|
||||
// CHECK-NEXT: [[BASE:%.*]] = ptrtoint [10 x [10 x i32]]* [[ARR]] to i64, !nosanitize
|
||||
// CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize
|
||||
// CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize
|
||||
// CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize
|
||||
// CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize
|
||||
// CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0, !nosanitize
|
||||
// CHECK-DAG: [[OFFSETVALID:%.*]] = xor i1 [[OFFSETOFLOW]], true, !nosanitize
|
||||
// CHECK-DAG: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize
|
||||
// CHECK: [[VALID:%.*]] = and i1 [[OFFSETVALID]], [[DIFFVALID]], !nosanitize
|
||||
// CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize
|
||||
// CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize
|
||||
// CHECK: [[VALID:%.*]] = and i1 [[DIFFVALID]], [[OFFSETVALID]], !nosanitize
|
||||
// CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize
|
||||
|
||||
@ -101,6 +119,24 @@ void pointer_array(int **arr, int k) {
|
||||
arr[k][k];
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @pointer_array_unsigned_indices
|
||||
void pointer_array_unsigned_indices(int **arr, unsigned k) {
|
||||
// CHECK-NOT: select
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
// CHECK-NOT: select
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
arr[k][k];
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @pointer_array_mixed_indices
|
||||
void pointer_array_mixed_indices(int **arr, int i, unsigned j) {
|
||||
// CHECK: select
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
// CHECK-NOT: select
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
arr[i][j];
|
||||
}
|
||||
|
||||
struct S1 {
|
||||
int pad1;
|
||||
union {
|
||||
@ -118,6 +154,7 @@ void struct_index(struct S1 *p) {
|
||||
// CHECK: getelementptr inbounds %struct.S1, %struct.S1* [[P:%.*]], i64 10
|
||||
// CHECK-NEXT: [[BASE:%.*]] = ptrtoint %struct.S1* [[P]] to i64, !nosanitize
|
||||
// CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 240, !nosanitize
|
||||
// CHECK: select
|
||||
// CHECK: @__ubsan_handle_pointer_overflow{{.*}} i64 [[BASE]], i64 [[COMPGEP]]) {{.*}}, !nosanitize
|
||||
|
||||
// CHECK-NOT: @__ubsan_handle_pointer_overflow
|
||||
@ -130,10 +167,12 @@ typedef void (*funcptr_t)(void);
|
||||
// CHECK-LABEL: define void @function_pointer_arith
|
||||
void function_pointer_arith(funcptr_t *p, int k) {
|
||||
// CHECK: add i64 {{.*}}, 8, !nosanitize
|
||||
// CHECK-NOT: select
|
||||
// CHECK: @__ubsan_handle_pointer_overflow{{.*}}
|
||||
++p;
|
||||
|
||||
// CHECK: @llvm.smul.with.overflow.i64(i64 8, i64 {{.*}}), !nosanitize
|
||||
// CHECK: select
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
p + k;
|
||||
}
|
||||
@ -145,11 +184,13 @@ void variable_len_array_arith(int n, int k) {
|
||||
|
||||
// CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[INC:%.*]]
|
||||
// CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 [[INC]]), !nosanitize
|
||||
// CHECK-NOT: select
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
++p;
|
||||
|
||||
// CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM:%.*]]
|
||||
// CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM]]), !nosanitize
|
||||
// CHECK: select
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
|
||||
p + k;
|
||||
}
|
||||
@ -157,6 +198,7 @@ void variable_len_array_arith(int n, int k) {
|
||||
// CHECK-LABEL: define void @objc_id
|
||||
void objc_id(id *p) {
|
||||
// CHECK: add i64 {{.*}}, 8, !nosanitize
|
||||
// CHECK-NOT: select
|
||||
// CHECK: @__ubsan_handle_pointer_overflow{{.*}}
|
||||
p++;
|
||||
}
|
||||
|
7
test/CodeGen/ubsan-volatile.c
Normal file
7
test/CodeGen/ubsan-volatile.c
Normal file
@ -0,0 +1,7 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=null,alignment,object-size,vptr -S -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
// CHECK: @volatile_null_deref
|
||||
void volatile_null_deref(volatile int *p) {
|
||||
// CHECK-NOT: call{{.*}}ubsan
|
||||
*p;
|
||||
}
|
@ -27,7 +27,5 @@ A f() {
|
||||
return c;
|
||||
}
|
||||
|
||||
// CHECK: !llvm.module.flags = !{{{.*}}}
|
||||
// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
|
||||
// CHECK: ![[link_opts]] = !{![[dyn_tls_init:[0-9]+]]}
|
||||
// CHECK: !llvm.linker.options = !{![[dyn_tls_init:[0-9]+]]}
|
||||
// CHECK: ![[dyn_tls_init]] = !{!"/include:___dyn_tls_init@12"}
|
||||
|
@ -1,4 +1,5 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 \
|
||||
// RUN: -emit-llvm %s -o - -disable-llvm-passes -Wno-coroutine -Wno-unused | FileCheck %s
|
||||
|
||||
namespace std {
|
||||
namespace experimental {
|
||||
@ -278,3 +279,50 @@ void AwaitLValue() {
|
||||
suspend_always lval;
|
||||
co_await lval;
|
||||
}
|
||||
|
||||
struct RefTag { };
|
||||
|
||||
struct AwaitResumeReturnsLValue {
|
||||
bool await_ready();
|
||||
void await_suspend(std::experimental::coroutine_handle<>);
|
||||
RefTag& await_resume();
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct std::experimental::coroutine_traits<void,double> {
|
||||
struct promise_type {
|
||||
void get_return_object();
|
||||
init_susp initial_suspend();
|
||||
final_susp final_suspend();
|
||||
void return_void();
|
||||
AwaitResumeReturnsLValue yield_value(int);
|
||||
};
|
||||
};
|
||||
|
||||
// Verifies that we don't crash when returning an lvalue from an await_resume()
|
||||
// expression.
|
||||
// CHECK-LABEL: define void @_Z18AwaitReturnsLValued(double)
|
||||
void AwaitReturnsLValue(double) {
|
||||
AwaitResumeReturnsLValue a;
|
||||
// CHECK: %[[AVAR:.+]] = alloca %struct.AwaitResumeReturnsLValue,
|
||||
// CHECK: %[[XVAR:.+]] = alloca %struct.RefTag*,
|
||||
|
||||
// CHECK: %[[YVAR:.+]] = alloca %struct.RefTag*,
|
||||
// CHECK-NEXT: %[[TMP1:.+]] = alloca %struct.AwaitResumeReturnsLValue,
|
||||
|
||||
// CHECK: %[[ZVAR:.+]] = alloca %struct.RefTag*,
|
||||
// CHECK-NEXT: %[[TMP2:.+]] = alloca %struct.AwaitResumeReturnsLValue,
|
||||
|
||||
// CHECK: %[[RES1:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[AVAR]])
|
||||
// CHECK-NEXT: store %struct.RefTag* %[[RES1]], %struct.RefTag** %[[XVAR]],
|
||||
RefTag& x = co_await a;
|
||||
|
||||
// CHECK: %[[RES2:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[TMP1]])
|
||||
// CHECK-NEXT: store %struct.RefTag* %[[RES2]], %struct.RefTag** %[[YVAR]],
|
||||
|
||||
RefTag& y = co_await AwaitResumeReturnsLValue{};
|
||||
// CHECK: %[[RES3:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[TMP2]])
|
||||
// CHECK-NEXT: store %struct.RefTag* %[[RES3]], %struct.RefTag** %[[ZVAR]],
|
||||
RefTag& z = co_yield 42;
|
||||
}
|
||||
|
@ -37,9 +37,8 @@ void use_at_available() {
|
||||
// CHECK_NO_GUARD-NOT: __clang_at_available_requires_core_foundation_framework
|
||||
// CHECK_NO_GUARD-NOT: CFBundleGetVersionNumber
|
||||
|
||||
// CHECK_LINK_OPT: !"Linker Options", ![[OPTS:[0-9]+]]
|
||||
// CHECK_LINK_OPT: ![[OPTS]] = !{![[FRAMEWORK:[0-9]+]]
|
||||
// CHECK_LINK_OPT: !llvm.linker.options = !{![[FRAMEWORK:[0-9]+]]
|
||||
// CHECK_LINK_OPT: ![[FRAMEWORK]] = !{!"-framework", !"CoreFoundation"}
|
||||
|
||||
// CHECK_NO_GUARD-NOT: "Linker Options"
|
||||
// CHECK_NO_GUARD-NOT: !llvm.linker.options
|
||||
// CHECK_NO_GUARD-NOT: CoreFoundation
|
||||
|
@ -3,6 +3,7 @@
|
||||
// RUN: %clang_cc1 -ast-print %t.1.c -o %t.2.c
|
||||
// RUN: diff %t.1.c %t.2.c
|
||||
// RUN: %clang_cc1 -ast-dump %s
|
||||
// RUN: %clang_cc1 -ast-dump-all %s
|
||||
// RUN: %clang_cc1 -print-decl-contexts %s
|
||||
|
||||
#include "c-language-features.inc"
|
||||
|
@ -3,6 +3,7 @@
|
||||
// RUN: %clang_cc1 -std=c++14 -ast-print %t.1.cpp -o %t.2.cpp
|
||||
// RUN: diff %t.1.cpp %t.2.cpp
|
||||
// RUN: %clang_cc1 -std=c++14 -ast-dump %s
|
||||
// RUN: %clang_cc1 -std=c++14 -ast-dump-all %s
|
||||
// RUN: %clang_cc1 -std=c++14 -print-decl-contexts %s
|
||||
// RUN: %clang_cc1 -std=c++14 -fdump-record-layouts %s
|
||||
|
||||
|
@ -1,3 +1,15 @@
|
||||
// RUN: %clang -### \
|
||||
// RUN: -M -MM %s 2> %t
|
||||
// RUN: not grep '"-sys-header-deps"' %t
|
||||
|
||||
// RUN: %clang -M -MM %s 2> %t
|
||||
// RUN: not grep "warning" %t
|
||||
|
||||
// RUN: %clang -MMD -MD %s 2> %t || true
|
||||
// RUN: grep "warning" %t
|
||||
|
||||
#warning "This warning shouldn't show up with -M and -MM"
|
||||
int main (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: c-index-test core -print-source-symbols -- %s -std=c++14 -target x86_64-apple-macosx10.7 | FileCheck %s
|
||||
// RUN: c-index-test core -print-source-symbols -- %s -std=c++1z -target x86_64-apple-macosx10.7 | FileCheck %s
|
||||
|
||||
// CHECK: [[@LINE+1]]:7 | class/C++ | Cls | [[Cls_USR:.*]] | <no-cgname> | Def | rel: 0
|
||||
class Cls { public:
|
||||
@ -433,3 +433,45 @@ template<typename T>
|
||||
T varDecl = T();
|
||||
|
||||
} // end namespace ensureDefaultTemplateParamsAreRecordedOnce
|
||||
|
||||
struct StaticAssertRef {
|
||||
static constexpr bool constVar = true;
|
||||
};
|
||||
|
||||
static_assert(StaticAssertRef::constVar, "index static asserts");
|
||||
// CHECK: [[@LINE-1]]:32 | static-property/C++ | constVar | c:@S@StaticAssertRef@constVar | __ZN15StaticAssertRef8constVarE | Ref | rel: 0
|
||||
// CHECK: [[@LINE-2]]:15 | struct/C++ | StaticAssertRef | c:@S@StaticAssertRef | <no-cgname> | Ref | rel: 0
|
||||
|
||||
void staticAssertInFn() {
|
||||
static_assert(StaticAssertRef::constVar, "index static asserts");
|
||||
// CHECK: [[@LINE-1]]:34 | static-property/C++ | constVar | c:@S@StaticAssertRef@constVar | __ZN15StaticAssertRef8constVarE | Ref,RelCont | rel: 1
|
||||
// CHECK-NEXT: RelCont | staticAssertInFn | c:@F@staticAssertInFn#
|
||||
// CHECK: [[@LINE-3]]:17 | struct/C++ | StaticAssertRef | c:@S@StaticAssertRef | <no-cgname> | Ref,RelCont | rel: 1
|
||||
// CHECK-NEXT: RelCont | staticAssertInFn | c:@F@staticAssertInFn#
|
||||
}
|
||||
|
||||
namespace cpp17structuredBinding {
|
||||
|
||||
struct Cpp17StructuredBinding {
|
||||
int x, y;
|
||||
|
||||
Cpp17StructuredBinding(int x, int y): x(x), y(y) { }
|
||||
};
|
||||
|
||||
auto [structuredBinding1, structuredBinding2] = Cpp17StructuredBinding(Record::C, 0);
|
||||
// CHECK: [[@LINE-1]]:7 | variable/C++ | structuredBinding1 | c:@N@cpp17structuredBinding@structuredBinding1 | <no-cgname> | Decl,RelChild | rel: 1
|
||||
// CHECK-NEXT: RelChild | cpp17structuredBinding | c:@N@cpp17structuredBinding
|
||||
// CHECK: [[@LINE-3]]:27 | variable/C++ | structuredBinding2 | c:@N@cpp17structuredBinding@structuredBinding2 | <no-cgname> | Decl,RelChild | rel: 1
|
||||
// CHECK-NEXT: RelChild | cpp17structuredBinding | c:@N@cpp17structuredBinding
|
||||
|
||||
void localStructuredBindingAndRef() {
|
||||
int ref = structuredBinding1;
|
||||
// CHECK: [[@LINE-1]]:13 | variable/C++ | structuredBinding1 | c:@N@cpp17structuredBinding@structuredBinding1 | <no-cgname> | Ref,Read,RelCont | rel: 1
|
||||
// CHECK-NEXT: RelCont | localStructuredBindingAndRef | c:@N@cpp17structuredBinding@F@localStructuredBindingAndRef#
|
||||
auto [localBinding1, localBinding2] = Cpp17StructuredBinding(ref, structuredBinding2);
|
||||
// CHECK: [[@LINE-1]]:69 | variable/C++ | structuredBinding2 | c:@N@cpp17structuredBinding@structuredBinding2 | <no-cgname> | Ref,Read,RelCont | rel: 1
|
||||
// CHECK-NEXT: RelCont | localStructuredBindingAndRef | c:@N@cpp17structuredBinding@F@localStructuredBindingAndRef#
|
||||
// CHECK-NOT: localBinding
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,13 +8,15 @@ enum {
|
||||
|
||||
enum {
|
||||
old_enum_plat
|
||||
} __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7)
|
||||
} __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7)));
|
||||
|
||||
// RUN: c-index-test -test-load-source all %s > %t
|
||||
// RUN: FileCheck -check-prefix=CHECK-1 %s < %t
|
||||
// RUN: FileCheck -check-prefix=CHECK-2 %s < %t
|
||||
// CHECK-1: (ios, introduced=3.2, deprecated=4.1)
|
||||
// CHECK-2: (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
|
||||
void bar(void) __attribute__((availability(macosx,introduced=10.4))) __attribute__((availability(macosx,obsoleted=10.6))) __attribute__((availability(ios,introduced=3.2))) __attribute__((availability(macosx,deprecated=10.5,message="use foobar")));
|
||||
|
||||
// CHECK-2: EnumConstantDecl=old_enum:6:3 (Definition) (deprecated)
|
||||
// CHECK-2: EnumConstantDecl=old_enum_plat:10:3 {{.*}} (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
|
||||
void bar2(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7))) __attribute__((availability(ios,introduced=3.2,deprecated=10.0))) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7))) __attribute__((availability(ios,introduced=3.2,deprecated=10.0)));
|
||||
|
||||
// RUN: c-index-test -test-load-source all %s | FileCheck %s
|
||||
// CHECK: FunctionDecl=foo:3:6{{.*}}(ios, introduced=3.2, deprecated=4.1) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
|
||||
// CHECK: EnumConstantDecl=old_enum:6:3 (Definition) (deprecated)
|
||||
// CHECK: EnumConstantDecl=old_enum_plat:10:3 {{.*}} (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
|
||||
// CHECK: FunctionDecl=bar:13:6{{.*}}(ios, introduced=3.2) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.6, message="use foobar")
|
||||
// CHECK: FunctionDecl=bar2:15:6{{.*}}(ios, introduced=3.2, deprecated=10.0) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
|
||||
|
4
test/Misc/pr32207.c
Normal file
4
test/Misc/pr32207.c
Normal file
@ -0,0 +1,4 @@
|
||||
// test for r305179
|
||||
// RUN: %clang_cc1 -emit-llvm -O -mllvm -print-after-all %s -o %t 2>&1 | FileCheck %s
|
||||
// CHECK: *** IR Dump After Function Integration/Inlining ***
|
||||
void foo() {}
|
@ -36,9 +36,7 @@ int use_autolink_sub3() {
|
||||
|
||||
// NOTE: "autolink_sub" is intentionally not linked.
|
||||
|
||||
// CHECK: !llvm.module.flags = !{{{.*}}}
|
||||
// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[AUTOLINK_OPTIONS:[0-9]+]]}
|
||||
// CHECK: ![[AUTOLINK_OPTIONS]] = !{![[AUTOLINK_PCH:[0-9]+]], ![[AUTOLINK_FRAMEWORK:[0-9]+]], ![[AUTOLINK:[0-9]+]], ![[DEPENDSONMODULE:[0-9]+]], ![[MODULE:[0-9]+]], ![[NOUMBRELLA:[0-9]+]]}
|
||||
// CHECK: !llvm.linker.options = !{![[AUTOLINK_PCH:[0-9]+]], ![[AUTOLINK_FRAMEWORK:[0-9]+]], ![[AUTOLINK:[0-9]+]], ![[DEPENDSONMODULE:[0-9]+]], ![[MODULE:[0-9]+]], ![[NOUMBRELLA:[0-9]+]]}
|
||||
// CHECK: ![[AUTOLINK_PCH]] = !{!"{{(\\01|-l|/DEFAULTLIB:)}}autolink_from_pch{{(\.lib)?}}"}
|
||||
// CHECK: ![[AUTOLINK_FRAMEWORK]] = !{!"-framework", !"autolink_framework"}
|
||||
// CHECK: ![[AUTOLINK]] = !{!"{{(\\01|-l|/DEFAULTLIB:)}}autolink{{(\.lib)?}}"}
|
||||
@ -47,4 +45,4 @@ int use_autolink_sub3() {
|
||||
// CHECK: ![[NOUMBRELLA]] = !{!"-framework", !"NoUmbrella"}
|
||||
|
||||
// CHECK-AUTOLINK-DISABLED: !llvm.module.flags
|
||||
// CHECK-AUTOLINK-DISABLED-NOT: "Linker Options"
|
||||
// CHECK-AUTOLINK-DISABLED-NOT: !llvm.linker.options
|
||||
|
@ -8,10 +8,8 @@ int f() {
|
||||
return foo();
|
||||
}
|
||||
|
||||
// CHECK: !llvm.module.flags = !{{{.*}}}
|
||||
// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[AUTOLINK_OPTIONS:[0-9]+]]}
|
||||
// CHECK: ![[AUTOLINK_OPTIONS]] = !{![[AUTOLINK_FRAMEWORK:[0-9]+]]}
|
||||
// CHECK: !llvm.linker.options = !{![[AUTOLINK_FRAMEWORK:[0-9]+]]}
|
||||
// CHECK: ![[AUTOLINK_FRAMEWORK]] = !{!"-framework", !"AutolinkTBD"}
|
||||
|
||||
// CHECK-AUTOLINK-DISABLED: !llvm.module.flags
|
||||
// CHECK-AUTOLINK-DISABLED-NOT: "Linker Options"
|
||||
// CHECK-AUTOLINK-DISABLED-NOT: !llvm.linker.options
|
||||
|
@ -1,7 +1,6 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -fmodule-name=Clib %s -I %S/Inputs/module-impl-with-link -emit-llvm -o - | FileCheck %s
|
||||
#include "foo.h"
|
||||
// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[LINK_OPTIONS:[0-9]+]]}
|
||||
// Make sure we don't generate linker option for module Clib since this TU is
|
||||
// an implementation of Clib.
|
||||
// CHECK: ![[LINK_OPTIONS]] = !{}
|
||||
// CHECK: !llvm.linker.options = !{}
|
||||
|
@ -486,7 +486,8 @@ struct S12 {
|
||||
};
|
||||
#else
|
||||
S12 s12;
|
||||
// TODO: This should produce an error.
|
||||
// expected-error@second.h:* {{'Method::S12' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter without a default argument}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter with a default argument}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
@ -499,7 +500,8 @@ struct S13 {
|
||||
};
|
||||
#else
|
||||
S13 s13;
|
||||
// TODO: This should produce an error.
|
||||
// expected-error@second.h:* {{'Method::S13' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter with a default argument}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter with a different default argument}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
@ -586,6 +588,57 @@ S3 s3;
|
||||
// expected-error@first.h:* {{'TypeDef::S3::a' from module 'FirstModule' is not present in definition of 'TypeDef::S3' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'a' does not match}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S4 {
|
||||
typedef int a;
|
||||
typedef int b;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S4 {
|
||||
typedef int b;
|
||||
typedef int a;
|
||||
};
|
||||
#else
|
||||
S4 s4;
|
||||
// expected-error@second.h:* {{'TypeDef::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found typedef name 'b'}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found typedef name 'a'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S5 {
|
||||
typedef int a;
|
||||
typedef int b;
|
||||
int x;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S5 {
|
||||
int x;
|
||||
typedef int b;
|
||||
typedef int a;
|
||||
};
|
||||
#else
|
||||
S5 s5;
|
||||
// expected-error@second.h:* {{'TypeDef::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found typedef}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
typedef float F;
|
||||
struct S6 {
|
||||
typedef int a;
|
||||
typedef F b;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S6 {
|
||||
typedef int a;
|
||||
typedef float b;
|
||||
};
|
||||
#else
|
||||
S6 s6;
|
||||
// expected-error@second.h:* {{'TypeDef::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found typedef 'b' with underlying type 'float'}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found typedef 'b' with different underlying type 'TypeDef::F' (aka 'float')}}
|
||||
#endif
|
||||
} // namespace TypeDef
|
||||
|
||||
namespace Using {
|
||||
@ -632,6 +685,57 @@ S3 s3;
|
||||
// expected-error@first.h:* {{'Using::S3::a' from module 'FirstModule' is not present in definition of 'Using::S3' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'a' does not match}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S4 {
|
||||
using a = int;
|
||||
using b = int;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S4 {
|
||||
using b = int;
|
||||
using a = int;
|
||||
};
|
||||
#else
|
||||
S4 s4;
|
||||
// expected-error@second.h:* {{'Using::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias name 'b'}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found type alias name 'a'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S5 {
|
||||
using a = int;
|
||||
using b = int;
|
||||
int x;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S5 {
|
||||
int x;
|
||||
using b = int;
|
||||
using a = int;
|
||||
};
|
||||
#else
|
||||
S5 s5;
|
||||
// expected-error@second.h:* {{'Using::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found type alias}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
typedef float F;
|
||||
struct S6 {
|
||||
using a = int;
|
||||
using b = F;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S6 {
|
||||
using a = int;
|
||||
using b = float;
|
||||
};
|
||||
#else
|
||||
S6 s6;
|
||||
// expected-error@second.h:* {{'Using::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'b' with underlying type 'float'}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found type alias 'b' with different underlying type 'Using::F' (aka 'float')}}
|
||||
#endif
|
||||
} // namespace Using
|
||||
|
||||
namespace RecordType {
|
||||
@ -900,6 +1004,289 @@ S2 s2;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace TemplateArgument {
|
||||
#if defined(FIRST)
|
||||
template <class> struct U1{};
|
||||
struct S1 {
|
||||
U1<int> x;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
template <int> struct U1{};
|
||||
struct S1 {
|
||||
U1<1> x;
|
||||
};
|
||||
#else
|
||||
S1 s1;
|
||||
// expected-error@first.h:* {{'TemplateArgument::S1::x' from module 'FirstModule' is not present in definition of 'TemplateArgument::S1' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'x' does not match}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
template <int> struct U2{};
|
||||
struct S2 {
|
||||
using T = U2<2>;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
template <int> struct U2{};
|
||||
struct S2 {
|
||||
using T = U2<(2)>;
|
||||
};
|
||||
#else
|
||||
S2 s2;
|
||||
// expected-error@second.h:* {{'TemplateArgument::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'T' with underlying type 'U2<(2)>'}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found type alias 'T' with different underlying type 'U2<2>'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
template <int> struct U3{};
|
||||
struct S3 {
|
||||
using T = U3<2>;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
template <int> struct U3{};
|
||||
struct S3 {
|
||||
using T = U3<1 + 1>;
|
||||
};
|
||||
#else
|
||||
S3 s3;
|
||||
// expected-error@second.h:* {{'TemplateArgument::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'T' with underlying type 'U3<1 + 1>'}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found type alias 'T' with different underlying type 'U3<2>'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
template<class> struct T4a {};
|
||||
template <template <class> class T> struct U4 {};
|
||||
struct S4 {
|
||||
U4<T4a> x;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
template<class> struct T4b {};
|
||||
template <template <class> class T> struct U4 {};
|
||||
struct S4 {
|
||||
U4<T4b> x;
|
||||
};
|
||||
#else
|
||||
S4 s4;
|
||||
// expected-error@first.h:* {{'TemplateArgument::S4::x' from module 'FirstModule' is not present in definition of 'TemplateArgument::S4' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'x' does not match}}
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace TemplateTypeParmType {
|
||||
#if defined(FIRST)
|
||||
template <class T1, class T2>
|
||||
struct S1 {
|
||||
T1 x;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
template <class T1, class T2>
|
||||
struct S1 {
|
||||
T2 x;
|
||||
};
|
||||
#else
|
||||
using TemplateTypeParmType::S1;
|
||||
// expected-error@first.h:* {{'TemplateTypeParmType::S1::x' from module 'FirstModule' is not present in definition of 'S1<T1, T2>' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'x' does not match}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
template <int ...Ts>
|
||||
struct U2 {};
|
||||
template <int T, int U>
|
||||
class S2 {
|
||||
typedef U2<U, T> type;
|
||||
type x;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
template <int ...Ts>
|
||||
struct U2 {};
|
||||
template <int T, int U>
|
||||
class S2 {
|
||||
typedef U2<T, U> type;
|
||||
type x;
|
||||
};
|
||||
#else
|
||||
using TemplateTypeParmType::S2;
|
||||
// expected-error@first.h:* {{'TemplateTypeParmType::S2::x' from module 'FirstModule' is not present in definition of 'S2<T, U>' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'x' does not match}}
|
||||
// expected-error@first.h:* {{'TemplateTypeParmType::S2::type' from module 'FirstModule' is not present in definition of 'S2<T, U>' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'type' does not match}}
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace VarDecl {
|
||||
#if defined(FIRST)
|
||||
struct S1 {
|
||||
static int x;
|
||||
static int y;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S1 {
|
||||
static int y;
|
||||
static int x;
|
||||
};
|
||||
#else
|
||||
S1 s1;
|
||||
// expected-error@second.h:* {{'VarDecl::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member with name 'y'}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found data member with name 'x'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S2 {
|
||||
static int x;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
using I = int;
|
||||
struct S2 {
|
||||
static I x;
|
||||
};
|
||||
#else
|
||||
S2 s2;
|
||||
// expected-error@second.h:* {{'VarDecl::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with type 'VarDecl::I' (aka 'int')}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' with different type 'int'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S3 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S3 {
|
||||
static const int x;
|
||||
};
|
||||
#else
|
||||
S3 s3;
|
||||
// expected-error@second.h:* {{'VarDecl::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with an initializer}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' without an initializer}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S4 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S4 {
|
||||
static const int x = 2;
|
||||
};
|
||||
#else
|
||||
S4 s4;
|
||||
// expected-error@second.h:* {{'VarDecl::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with an initializer}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' with a different initializer}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S5 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S5 {
|
||||
static constexpr int x = 1;
|
||||
};
|
||||
#else
|
||||
S5 s5;
|
||||
// expected-error@second.h:* {{'VarDecl::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' is not constexpr}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' is constexpr}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S6 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S6 {
|
||||
static const int y = 1;
|
||||
};
|
||||
#else
|
||||
S6 s6;
|
||||
// expected-error@first.h:* {{'VarDecl::S6::x' from module 'FirstModule' is not present in definition of 'VarDecl::S6' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{definition has no member 'x'}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S7 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S7 {
|
||||
static const unsigned x = 1;
|
||||
};
|
||||
#else
|
||||
S7 s7;
|
||||
// expected-error@first.h:* {{'VarDecl::S7::x' from module 'FirstModule' is not present in definition of 'VarDecl::S7' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'x' does not match}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S8 {
|
||||
public:
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S8 {
|
||||
static const int x = 1;
|
||||
public:
|
||||
};
|
||||
#else
|
||||
S8 s8;
|
||||
// expected-error@second.h:* {{'VarDecl::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
struct S9 {
|
||||
static const int x = 1;
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
struct S9 {
|
||||
static int x;
|
||||
};
|
||||
#else
|
||||
S9 s9;
|
||||
// expected-error@first.h:* {{'VarDecl::S9::x' from module 'FirstModule' is not present in definition of 'VarDecl::S9' in module 'SecondModule'}}
|
||||
// expected-note@second.h:* {{declaration of 'x' does not match}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
template <typename T>
|
||||
struct S {
|
||||
struct R {
|
||||
void foo(T x = 0) {}
|
||||
};
|
||||
};
|
||||
#elif defined(SECOND)
|
||||
template <typename T>
|
||||
struct S {
|
||||
struct R {
|
||||
void foo(T x = 1) {}
|
||||
};
|
||||
};
|
||||
#else
|
||||
void run() {
|
||||
S<int>::R().foo();
|
||||
}
|
||||
// expected-error@second.h:* {{'VarDecl::S::R' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'foo' with 1st parameter with a default argument}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'foo' with 1st parameter with a different default argument}}
|
||||
#endif
|
||||
|
||||
#if defined(FIRST)
|
||||
template <typename alpha> struct Bravo {
|
||||
void charlie(bool delta = false) {}
|
||||
};
|
||||
typedef Bravo<char> echo;
|
||||
echo foxtrot;
|
||||
#elif defined(SECOND)
|
||||
template <typename alpha> struct Bravo {
|
||||
void charlie(bool delta = (false)) {}
|
||||
};
|
||||
typedef Bravo<char> echo;
|
||||
echo foxtrot;
|
||||
#else
|
||||
Bravo<char> golf;
|
||||
// expected-error@second.h:* {{'VarDecl::Bravo' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'charlie' with 1st parameter with a default argument}}
|
||||
// expected-note@first.h:* {{but in 'FirstModule' found method 'charlie' with 1st parameter with a different default argument}}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Interesting cases that should not cause errors. struct S should not error
|
||||
// while struct T should error at the access specifier mismatch at the end.
|
||||
namespace AllDecls {
|
||||
|
@ -151,14 +151,6 @@ uint64_t check_integer_overflows(int i) {
|
||||
uint64_t *b;
|
||||
uint64_t b2 = b[4608 * 1024 * 1024] + 1;
|
||||
|
||||
// expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}}
|
||||
f0(4608 * 1024 * 1024);
|
||||
f0(4608ul * 1024 * 1024);
|
||||
// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
|
||||
f1(4608 * 1024 * 1024, 4608 * 1024 * 1024);
|
||||
// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
|
||||
f2(4608 * 1024 * 1024, 4608 * 1024 * 1024);
|
||||
|
||||
// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
|
||||
int j1 = i ? (4608 * 1024 * 1024) : (4608 * 1024 * 1024);
|
||||
|
||||
|
7
test/Sema/xray-log-args-class.cpp
Normal file
7
test/Sema/xray-log-args-class.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c++11 -x c++
|
||||
|
||||
class Class {
|
||||
[[clang::xray_always_instrument, clang::xray_log_args(1)]] void Method();
|
||||
[[clang::xray_log_args(-1)]] void Invalid(); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}}
|
||||
[[clang::xray_log_args("invalid")]] void InvalidStringArg(); // expected-error {{'xray_log_args'}}
|
||||
};
|
165
test/SemaCXX/co_await-range-for.cpp
Normal file
165
test/SemaCXX/co_await-range-for.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \
|
||||
// RUN: -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \
|
||||
// RUN: -fblocks
|
||||
#include "Inputs/std-coroutine.h"
|
||||
|
||||
using namespace std::experimental;
|
||||
|
||||
|
||||
template <class Begin>
|
||||
struct Awaiter {
|
||||
bool await_ready();
|
||||
void await_suspend(coroutine_handle<>);
|
||||
Begin await_resume();
|
||||
};
|
||||
|
||||
template <class Iter> struct BeginTag { BeginTag() = delete; };
|
||||
template <class Iter> struct IncTag { IncTag() = delete; };
|
||||
|
||||
template <class Iter, bool Delete = false>
|
||||
struct CoawaitTag { CoawaitTag() = delete; };
|
||||
|
||||
template <class T>
|
||||
struct Iter {
|
||||
using value_type = T;
|
||||
using reference = T &;
|
||||
using pointer = T *;
|
||||
|
||||
IncTag<Iter> operator++();
|
||||
reference operator*();
|
||||
pointer operator->();
|
||||
};
|
||||
template <class T> bool operator==(Iter<T>, Iter<T>);
|
||||
template <class T> bool operator!=(Iter<T>, Iter<T>);
|
||||
|
||||
template <class T>
|
||||
struct Range {
|
||||
BeginTag<Iter<T>> begin();
|
||||
Iter<T> end();
|
||||
};
|
||||
|
||||
struct MyForLoopArrayAwaiter {
|
||||
struct promise_type {
|
||||
MyForLoopArrayAwaiter get_return_object() { return {}; }
|
||||
void return_void();
|
||||
void unhandled_exception();
|
||||
suspend_never initial_suspend();
|
||||
suspend_never final_suspend();
|
||||
template <class T>
|
||||
Awaiter<T *> await_transform(T *) = delete; // expected-note {{explicitly deleted}}
|
||||
};
|
||||
};
|
||||
MyForLoopArrayAwaiter g() {
|
||||
int arr[10] = {0};
|
||||
for co_await(auto i : arr) {}
|
||||
// expected-error@-1 {{call to deleted member function 'await_transform'}}
|
||||
// expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
|
||||
}
|
||||
|
||||
struct ForLoopAwaiterBadBeginTransform {
|
||||
struct promise_type {
|
||||
ForLoopAwaiterBadBeginTransform get_return_object();
|
||||
void return_void();
|
||||
void unhandled_exception();
|
||||
suspend_never initial_suspend();
|
||||
suspend_never final_suspend();
|
||||
|
||||
template <class T>
|
||||
Awaiter<T> await_transform(BeginTag<T>) = delete; // expected-note 1+ {{explicitly deleted}}
|
||||
|
||||
template <class T>
|
||||
CoawaitTag<T> await_transform(IncTag<T>); // expected-note 1+ {{candidate}}
|
||||
};
|
||||
};
|
||||
ForLoopAwaiterBadBeginTransform bad_begin() {
|
||||
Range<int> R;
|
||||
for co_await(auto i : R) {}
|
||||
// expected-error@-1 {{call to deleted member function 'await_transform'}}
|
||||
// expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
|
||||
}
|
||||
template <class Dummy>
|
||||
ForLoopAwaiterBadBeginTransform bad_begin_template(Dummy) {
|
||||
Range<Dummy> R;
|
||||
for co_await(auto i : R) {}
|
||||
// expected-error@-1 {{call to deleted member function 'await_transform'}}
|
||||
// expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
|
||||
}
|
||||
template ForLoopAwaiterBadBeginTransform bad_begin_template(int); // expected-note {{requested here}}
|
||||
|
||||
template <class Iter>
|
||||
Awaiter<Iter> operator co_await(CoawaitTag<Iter, true>) = delete;
|
||||
// expected-note@-1 1+ {{explicitly deleted}}
|
||||
|
||||
struct ForLoopAwaiterBadIncTransform {
|
||||
struct promise_type {
|
||||
ForLoopAwaiterBadIncTransform get_return_object();
|
||||
void return_void();
|
||||
void unhandled_exception();
|
||||
suspend_never initial_suspend();
|
||||
suspend_never final_suspend();
|
||||
|
||||
template <class T>
|
||||
Awaiter<T> await_transform(BeginTag<T> e);
|
||||
|
||||
template <class T>
|
||||
CoawaitTag<T, true> await_transform(IncTag<T>);
|
||||
};
|
||||
};
|
||||
ForLoopAwaiterBadIncTransform bad_inc_transform() {
|
||||
Range<float> R;
|
||||
for co_await(auto i : R) {}
|
||||
// expected-error@-1 {{overload resolution selected deleted operator 'co_await'}}
|
||||
// expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range<float>'}}
|
||||
}
|
||||
|
||||
template <class Dummy>
|
||||
ForLoopAwaiterBadIncTransform bad_inc_transform_template(Dummy) {
|
||||
Range<Dummy> R;
|
||||
for co_await(auto i : R) {}
|
||||
// expected-error@-1 {{overload resolution selected deleted operator 'co_await'}}
|
||||
// expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range<long>'}}
|
||||
}
|
||||
template ForLoopAwaiterBadIncTransform bad_inc_transform_template(long); // expected-note {{requested here}}
|
||||
|
||||
// Ensure we mark and check the function as a coroutine even if it's
|
||||
// never instantiated.
|
||||
template <class T>
|
||||
constexpr void never_instant(T) {
|
||||
static_assert(sizeof(T) != sizeof(T), "function should not be instantiated");
|
||||
for co_await(auto i : foo(T{})) {}
|
||||
// expected-error@-1 {{'co_await' cannot be used in a constexpr function}}
|
||||
}
|
||||
|
||||
namespace NS {
|
||||
struct ForLoopAwaiterCoawaitLookup {
|
||||
struct promise_type {
|
||||
ForLoopAwaiterCoawaitLookup get_return_object();
|
||||
void return_void();
|
||||
void unhandled_exception();
|
||||
suspend_never initial_suspend();
|
||||
suspend_never final_suspend();
|
||||
template <class T>
|
||||
CoawaitTag<T, false> await_transform(BeginTag<T> e);
|
||||
template <class T>
|
||||
Awaiter<T> await_transform(IncTag<T>);
|
||||
};
|
||||
};
|
||||
} // namespace NS
|
||||
using NS::ForLoopAwaiterCoawaitLookup;
|
||||
|
||||
template <class T>
|
||||
ForLoopAwaiterCoawaitLookup test_coawait_lookup(T) {
|
||||
Range<T> R;
|
||||
for co_await(auto i : R) {}
|
||||
// expected-error@-1 {{no member named 'await_ready' in 'CoawaitTag<Iter<int>, false>'}}
|
||||
}
|
||||
template ForLoopAwaiterCoawaitLookup test_coawait_lookup(int); // expected-note {{requested here}}
|
||||
|
||||
// FIXME: This test should fail as well since the newly declared operator co_await
|
||||
// should not be found by lookup.
|
||||
namespace NS2 {
|
||||
template <class Iter>
|
||||
Awaiter<Iter> operator co_await(CoawaitTag<Iter, false>);
|
||||
}
|
||||
using NS2::operator co_await;
|
||||
template ForLoopAwaiterCoawaitLookup test_coawait_lookup(long);
|
@ -70,4 +70,10 @@ int error_recovery() {
|
||||
return foobar_; // expected-error {{undeclared identifier 'foobar_'}}
|
||||
}
|
||||
|
||||
// PR32172
|
||||
template <class T> void dependent_foreach(T t) {
|
||||
for (auto [a,b,c] : t)
|
||||
a,b,c;
|
||||
}
|
||||
|
||||
// FIXME: by-value array copies
|
||||
|
@ -169,6 +169,13 @@ void N::f() { } // okay
|
||||
struct Y; // expected-note{{forward declaration of 'Y'}}
|
||||
Y::foo y; // expected-error{{incomplete type 'Y' named in nested name specifier}}
|
||||
|
||||
namespace PR25156 {
|
||||
struct Y; // expected-note{{forward declaration of 'PR25156::Y'}}
|
||||
void foo() {
|
||||
Y::~Y(); // expected-error{{incomplete type 'PR25156::Y' named in nested name specifier}}
|
||||
}
|
||||
}
|
||||
|
||||
X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}}
|
||||
|
||||
struct foo_S {
|
||||
|
@ -142,11 +142,14 @@ void test_templated() {
|
||||
auto implicit_by_reference = [&] { i++; };
|
||||
|
||||
auto explicit_by_value_used = [i] { return i + 1; };
|
||||
auto explicit_by_value_used_generic = [i](auto c) { return i + 1; };
|
||||
auto explicit_by_value_used_void = [i] { (void)i; };
|
||||
|
||||
auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
|
||||
auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
|
||||
auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}}
|
||||
auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
|
||||
auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
|
||||
|
||||
auto explicit_by_reference_used = [&i] { i++; };
|
||||
auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}}
|
||||
@ -161,6 +164,8 @@ void test_templated() {
|
||||
auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}}
|
||||
auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{};
|
||||
auto explicit_initialized_value_with_side_effect = [j = side_effect()]{};
|
||||
auto explicit_initialized_value_generic_used = [i = 1](auto c) mutable { i++; };
|
||||
auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}}
|
||||
|
||||
auto nested = [&i] {
|
||||
auto explicit_by_value_used = [i] { return i + 1; };
|
||||
|
@ -324,6 +324,8 @@ def filter_by_extension(dictionary, allowed_extensions):
|
||||
allowed_extensions = frozenset(allowed_extensions)
|
||||
for filename in list(dictionary.keys()):
|
||||
base_ext = filename.rsplit('.', 1)
|
||||
if len(base_ext) == 1 and '' in allowed_extensions:
|
||||
continue
|
||||
if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions:
|
||||
del dictionary[filename]
|
||||
|
||||
|
@ -7216,15 +7216,11 @@ static CXVersion convertVersion(VersionTuple In) {
|
||||
return Out;
|
||||
}
|
||||
|
||||
static int getCursorPlatformAvailabilityForDecl(const Decl *D,
|
||||
int *always_deprecated,
|
||||
CXString *deprecated_message,
|
||||
int *always_unavailable,
|
||||
CXString *unavailable_message,
|
||||
CXPlatformAvailability *availability,
|
||||
int availability_size) {
|
||||
static void getCursorPlatformAvailabilityForDecl(
|
||||
const Decl *D, int *always_deprecated, CXString *deprecated_message,
|
||||
int *always_unavailable, CXString *unavailable_message,
|
||||
SmallVectorImpl<AvailabilityAttr *> &AvailabilityAttrs) {
|
||||
bool HadAvailAttr = false;
|
||||
int N = 0;
|
||||
for (auto A : D->attrs()) {
|
||||
if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(A)) {
|
||||
HadAvailAttr = true;
|
||||
@ -7236,7 +7232,7 @@ static int getCursorPlatformAvailabilityForDecl(const Decl *D,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(A)) {
|
||||
HadAvailAttr = true;
|
||||
if (always_unavailable)
|
||||
@ -7247,38 +7243,71 @@ static int getCursorPlatformAvailabilityForDecl(const Decl *D,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(A)) {
|
||||
AvailabilityAttrs.push_back(Avail);
|
||||
HadAvailAttr = true;
|
||||
if (N < availability_size) {
|
||||
availability[N].Platform
|
||||
= cxstring::createDup(Avail->getPlatform()->getName());
|
||||
availability[N].Introduced = convertVersion(Avail->getIntroduced());
|
||||
availability[N].Deprecated = convertVersion(Avail->getDeprecated());
|
||||
availability[N].Obsoleted = convertVersion(Avail->getObsoleted());
|
||||
availability[N].Unavailable = Avail->getUnavailable();
|
||||
availability[N].Message = cxstring::createDup(Avail->getMessage());
|
||||
}
|
||||
++N;
|
||||
}
|
||||
}
|
||||
|
||||
if (!HadAvailAttr)
|
||||
if (const EnumConstantDecl *EnumConst = dyn_cast<EnumConstantDecl>(D))
|
||||
return getCursorPlatformAvailabilityForDecl(
|
||||
cast<Decl>(EnumConst->getDeclContext()),
|
||||
always_deprecated,
|
||||
deprecated_message,
|
||||
always_unavailable,
|
||||
unavailable_message,
|
||||
availability,
|
||||
availability_size);
|
||||
|
||||
return N;
|
||||
cast<Decl>(EnumConst->getDeclContext()), always_deprecated,
|
||||
deprecated_message, always_unavailable, unavailable_message,
|
||||
AvailabilityAttrs);
|
||||
|
||||
if (AvailabilityAttrs.empty())
|
||||
return;
|
||||
|
||||
std::sort(AvailabilityAttrs.begin(), AvailabilityAttrs.end(),
|
||||
[](AvailabilityAttr *LHS, AvailabilityAttr *RHS) {
|
||||
return LHS->getPlatform() > RHS->getPlatform();
|
||||
});
|
||||
ASTContext &Ctx = D->getASTContext();
|
||||
auto It = std::unique(
|
||||
AvailabilityAttrs.begin(), AvailabilityAttrs.end(),
|
||||
[&Ctx](AvailabilityAttr *LHS, AvailabilityAttr *RHS) {
|
||||
if (LHS->getPlatform() != RHS->getPlatform())
|
||||
return false;
|
||||
|
||||
if (LHS->getIntroduced() == RHS->getIntroduced() &&
|
||||
LHS->getDeprecated() == RHS->getDeprecated() &&
|
||||
LHS->getObsoleted() == RHS->getObsoleted() &&
|
||||
LHS->getMessage() == RHS->getMessage() &&
|
||||
LHS->getReplacement() == RHS->getReplacement())
|
||||
return true;
|
||||
|
||||
if ((!LHS->getIntroduced().empty() && !RHS->getIntroduced().empty()) ||
|
||||
(!LHS->getDeprecated().empty() && !RHS->getDeprecated().empty()) ||
|
||||
(!LHS->getObsoleted().empty() && !RHS->getObsoleted().empty()))
|
||||
return false;
|
||||
|
||||
if (LHS->getIntroduced().empty() && !RHS->getIntroduced().empty())
|
||||
LHS->setIntroduced(Ctx, RHS->getIntroduced());
|
||||
|
||||
if (LHS->getDeprecated().empty() && !RHS->getDeprecated().empty()) {
|
||||
LHS->setDeprecated(Ctx, RHS->getDeprecated());
|
||||
if (LHS->getMessage().empty())
|
||||
LHS->setMessage(Ctx, RHS->getMessage());
|
||||
if (LHS->getReplacement().empty())
|
||||
LHS->setReplacement(Ctx, RHS->getReplacement());
|
||||
}
|
||||
|
||||
if (LHS->getObsoleted().empty() && !RHS->getObsoleted().empty()) {
|
||||
LHS->setObsoleted(Ctx, RHS->getObsoleted());
|
||||
if (LHS->getMessage().empty())
|
||||
LHS->setMessage(Ctx, RHS->getMessage());
|
||||
if (LHS->getReplacement().empty())
|
||||
LHS->setReplacement(Ctx, RHS->getReplacement());
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
AvailabilityAttrs.erase(It, AvailabilityAttrs.end());
|
||||
}
|
||||
|
||||
int clang_getCursorPlatformAvailability(CXCursor cursor,
|
||||
int *always_deprecated,
|
||||
int clang_getCursorPlatformAvailability(CXCursor cursor, int *always_deprecated,
|
||||
CXString *deprecated_message,
|
||||
int *always_unavailable,
|
||||
CXString *unavailable_message,
|
||||
@ -7300,14 +7329,29 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
|
||||
if (!D)
|
||||
return 0;
|
||||
|
||||
return getCursorPlatformAvailabilityForDecl(D, always_deprecated,
|
||||
deprecated_message,
|
||||
always_unavailable,
|
||||
unavailable_message,
|
||||
availability,
|
||||
availability_size);
|
||||
SmallVector<AvailabilityAttr *, 8> AvailabilityAttrs;
|
||||
getCursorPlatformAvailabilityForDecl(D, always_deprecated, deprecated_message,
|
||||
always_unavailable, unavailable_message,
|
||||
AvailabilityAttrs);
|
||||
for (const auto &Avail :
|
||||
llvm::enumerate(llvm::makeArrayRef(AvailabilityAttrs)
|
||||
.take_front(availability_size))) {
|
||||
availability[Avail.index()].Platform =
|
||||
cxstring::createDup(Avail.value()->getPlatform()->getName());
|
||||
availability[Avail.index()].Introduced =
|
||||
convertVersion(Avail.value()->getIntroduced());
|
||||
availability[Avail.index()].Deprecated =
|
||||
convertVersion(Avail.value()->getDeprecated());
|
||||
availability[Avail.index()].Obsoleted =
|
||||
convertVersion(Avail.value()->getObsoleted());
|
||||
availability[Avail.index()].Unavailable = Avail.value()->getUnavailable();
|
||||
availability[Avail.index()].Message =
|
||||
cxstring::createDup(Avail.value()->getMessage());
|
||||
}
|
||||
|
||||
return AvailabilityAttrs.size();
|
||||
}
|
||||
|
||||
|
||||
void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) {
|
||||
clang_disposeString(availability->Platform);
|
||||
clang_disposeString(availability->Message);
|
||||
|
@ -320,9 +320,10 @@ TEST_F(CommentLexerTest, DoxygenCommand4) {
|
||||
ASSERT_EQ(array_lengthof(Text), Toks.size());
|
||||
|
||||
for (size_t j = 0, e = Toks.size(); j != e; j++) {
|
||||
if(Toks[j].is(tok::text))
|
||||
if(Toks[j].is(tok::text)) {
|
||||
ASSERT_EQ(StringRef(Text[j]), Toks[j].getText())
|
||||
<< "index " << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -320,10 +320,12 @@ public:
|
||||
ExpectedName(ExpectedName) {}
|
||||
|
||||
void onEndOfTranslationUnit() override {
|
||||
if (ExpectedCount != -1)
|
||||
if (ExpectedCount != -1) {
|
||||
EXPECT_EQ(ExpectedCount, Count);
|
||||
if (!ExpectedName.empty())
|
||||
}
|
||||
if (!ExpectedName.empty()) {
|
||||
EXPECT_EQ(ExpectedName, Name);
|
||||
}
|
||||
Count = 0;
|
||||
Name.clear();
|
||||
}
|
||||
@ -346,8 +348,9 @@ public:
|
||||
}
|
||||
BoundNodes::IDToNodeMap::const_iterator I = M.find(Id);
|
||||
EXPECT_NE(M.end(), I);
|
||||
if (I != M.end())
|
||||
if (I != M.end()) {
|
||||
EXPECT_EQ(Nodes->getNodeAs<T>(Id), I->second.get<T>());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
EXPECT_TRUE(M.count(Id) == 0 ||
|
||||
|
@ -300,8 +300,9 @@ struct ScopedDir {
|
||||
EXPECT_FALSE(EC);
|
||||
}
|
||||
~ScopedDir() {
|
||||
if (Path != "")
|
||||
if (Path != "") {
|
||||
EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
|
||||
}
|
||||
}
|
||||
operator StringRef() { return Path.str(); }
|
||||
};
|
||||
@ -316,8 +317,9 @@ struct ScopedLink {
|
||||
EXPECT_FALSE(EC);
|
||||
}
|
||||
~ScopedLink() {
|
||||
if (Path != "")
|
||||
if (Path != "") {
|
||||
EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
|
||||
}
|
||||
}
|
||||
operator StringRef() { return Path.str(); }
|
||||
};
|
||||
|
@ -1310,6 +1310,141 @@ TEST_F(FormatTest, FormatsNamespaces) {
|
||||
Style));
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, FormatsCompactNamespaces) {
|
||||
FormatStyle Style = getLLVMStyle();
|
||||
Style.CompactNamespaces = true;
|
||||
|
||||
verifyFormat("namespace A { namespace B {\n"
|
||||
"}} // namespace A::B",
|
||||
Style);
|
||||
|
||||
EXPECT_EQ("namespace out { namespace in {\n"
|
||||
"}} // namespace out::in",
|
||||
format("namespace out {\n"
|
||||
"namespace in {\n"
|
||||
"} // namespace in\n"
|
||||
"} // namespace out",
|
||||
Style));
|
||||
|
||||
// Only namespaces which have both consecutive opening and end get compacted
|
||||
EXPECT_EQ("namespace out {\n"
|
||||
"namespace in1 {\n"
|
||||
"} // namespace in1\n"
|
||||
"namespace in2 {\n"
|
||||
"} // namespace in2\n"
|
||||
"} // namespace out",
|
||||
format("namespace out {\n"
|
||||
"namespace in1 {\n"
|
||||
"} // namespace in1\n"
|
||||
"namespace in2 {\n"
|
||||
"} // namespace in2\n"
|
||||
"} // namespace out",
|
||||
Style));
|
||||
|
||||
EXPECT_EQ("namespace out {\n"
|
||||
"int i;\n"
|
||||
"namespace in {\n"
|
||||
"int j;\n"
|
||||
"} // namespace in\n"
|
||||
"int k;\n"
|
||||
"} // namespace out",
|
||||
format("namespace out { int i;\n"
|
||||
"namespace in { int j; } // namespace in\n"
|
||||
"int k; } // namespace out",
|
||||
Style));
|
||||
|
||||
EXPECT_EQ("namespace A { namespace B { namespace C {\n"
|
||||
"}}} // namespace A::B::C\n",
|
||||
format("namespace A { namespace B {\n"
|
||||
"namespace C {\n"
|
||||
"}} // namespace B::C\n"
|
||||
"} // namespace A\n",
|
||||
Style));
|
||||
|
||||
Style.ColumnLimit = 40;
|
||||
EXPECT_EQ("namespace aaaaaaaaaa {\n"
|
||||
"namespace bbbbbbbbbb {\n"
|
||||
"}} // namespace aaaaaaaaaa::bbbbbbbbbb",
|
||||
format("namespace aaaaaaaaaa {\n"
|
||||
"namespace bbbbbbbbbb {\n"
|
||||
"} // namespace bbbbbbbbbb\n"
|
||||
"} // namespace aaaaaaaaaa",
|
||||
Style));
|
||||
|
||||
EXPECT_EQ("namespace aaaaaa { namespace bbbbbb {\n"
|
||||
"namespace cccccc {\n"
|
||||
"}}} // namespace aaaaaa::bbbbbb::cccccc",
|
||||
format("namespace aaaaaa {\n"
|
||||
"namespace bbbbbb {\n"
|
||||
"namespace cccccc {\n"
|
||||
"} // namespace cccccc\n"
|
||||
"} // namespace bbbbbb\n"
|
||||
"} // namespace aaaaaa",
|
||||
Style));
|
||||
Style.ColumnLimit = 80;
|
||||
|
||||
// Extra semicolon after 'inner' closing brace prevents merging
|
||||
EXPECT_EQ("namespace out { namespace in {\n"
|
||||
"}; } // namespace out::in",
|
||||
format("namespace out {\n"
|
||||
"namespace in {\n"
|
||||
"}; // namespace in\n"
|
||||
"} // namespace out",
|
||||
Style));
|
||||
|
||||
// Extra semicolon after 'outer' closing brace is conserved
|
||||
EXPECT_EQ("namespace out { namespace in {\n"
|
||||
"}}; // namespace out::in",
|
||||
format("namespace out {\n"
|
||||
"namespace in {\n"
|
||||
"} // namespace in\n"
|
||||
"}; // namespace out",
|
||||
Style));
|
||||
|
||||
Style.NamespaceIndentation = FormatStyle::NI_All;
|
||||
EXPECT_EQ("namespace out { namespace in {\n"
|
||||
" int i;\n"
|
||||
"}} // namespace out::in",
|
||||
format("namespace out {\n"
|
||||
"namespace in {\n"
|
||||
"int i;\n"
|
||||
"} // namespace in\n"
|
||||
"} // namespace out",
|
||||
Style));
|
||||
EXPECT_EQ("namespace out { namespace mid {\n"
|
||||
" namespace in {\n"
|
||||
" int j;\n"
|
||||
" } // namespace in\n"
|
||||
" int k;\n"
|
||||
"}} // namespace out::mid",
|
||||
format("namespace out { namespace mid {\n"
|
||||
"namespace in { int j; } // namespace in\n"
|
||||
"int k; }} // namespace out::mid",
|
||||
Style));
|
||||
|
||||
Style.NamespaceIndentation = FormatStyle::NI_Inner;
|
||||
EXPECT_EQ("namespace out { namespace in {\n"
|
||||
" int i;\n"
|
||||
"}} // namespace out::in",
|
||||
format("namespace out {\n"
|
||||
"namespace in {\n"
|
||||
"int i;\n"
|
||||
"} // namespace in\n"
|
||||
"} // namespace out",
|
||||
Style));
|
||||
EXPECT_EQ("namespace out { namespace mid { namespace in {\n"
|
||||
" int i;\n"
|
||||
"}}} // namespace out::mid::in",
|
||||
format("namespace out {\n"
|
||||
"namespace mid {\n"
|
||||
"namespace in {\n"
|
||||
"int i;\n"
|
||||
"} // namespace in\n"
|
||||
"} // namespace mid\n"
|
||||
"} // namespace out",
|
||||
Style));
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, FormatsExternC) { verifyFormat("extern \"C\" {\nint a;"); }
|
||||
|
||||
TEST_F(FormatTest, FormatsInlineASM) {
|
||||
@ -6239,6 +6374,35 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
|
||||
getLLVMStyleWithColumns(23));
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, PullEmptyFunctionDefinitionsIntoSingleLine) {
|
||||
FormatStyle MergeEmptyOnly = getLLVMStyle();
|
||||
MergeEmptyOnly.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
|
||||
verifyFormat("class C {\n"
|
||||
" int f() {}\n"
|
||||
"};",
|
||||
MergeEmptyOnly);
|
||||
verifyFormat("class C {\n"
|
||||
" int f() {\n"
|
||||
" return 42;\n"
|
||||
" }\n"
|
||||
"};",
|
||||
MergeEmptyOnly);
|
||||
verifyFormat("int f() {}", MergeEmptyOnly);
|
||||
verifyFormat("int f() {\n"
|
||||
" return 42;\n"
|
||||
"}",
|
||||
MergeEmptyOnly);
|
||||
|
||||
// Also verify behavior when BraceWrapping.AfterFunction = true
|
||||
MergeEmptyOnly.BreakBeforeBraces = FormatStyle::BS_Custom;
|
||||
MergeEmptyOnly.BraceWrapping.AfterFunction = true;
|
||||
verifyFormat("int f() {}", MergeEmptyOnly);
|
||||
verifyFormat("class C {\n"
|
||||
" int f() {}\n"
|
||||
"};",
|
||||
MergeEmptyOnly);
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, PullInlineFunctionDefinitionsIntoSingleLine) {
|
||||
FormatStyle MergeInlineOnly = getLLVMStyle();
|
||||
MergeInlineOnly.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
|
||||
@ -6250,6 +6414,101 @@ TEST_F(FormatTest, PullInlineFunctionDefinitionsIntoSingleLine) {
|
||||
" return 42;\n"
|
||||
"}",
|
||||
MergeInlineOnly);
|
||||
|
||||
// SFS_Inline implies SFS_Empty
|
||||
verifyFormat("class C {\n"
|
||||
" int f() {}\n"
|
||||
"};",
|
||||
MergeInlineOnly);
|
||||
verifyFormat("int f() {}", MergeInlineOnly);
|
||||
|
||||
// Also verify behavior when BraceWrapping.AfterFunction = true
|
||||
MergeInlineOnly.BreakBeforeBraces = FormatStyle::BS_Custom;
|
||||
MergeInlineOnly.BraceWrapping.AfterFunction = true;
|
||||
verifyFormat("class C {\n"
|
||||
" int f() { return 42; }\n"
|
||||
"};",
|
||||
MergeInlineOnly);
|
||||
verifyFormat("int f()\n"
|
||||
"{\n"
|
||||
" return 42;\n"
|
||||
"}",
|
||||
MergeInlineOnly);
|
||||
|
||||
// SFS_Inline implies SFS_Empty
|
||||
verifyFormat("int f() {}", MergeInlineOnly);
|
||||
verifyFormat("class C {\n"
|
||||
" int f() {}\n"
|
||||
"};",
|
||||
MergeInlineOnly);
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, SplitEmptyFunctionBody) {
|
||||
FormatStyle Style = getLLVMStyle();
|
||||
Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
|
||||
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
|
||||
Style.BraceWrapping.AfterFunction = true;
|
||||
Style.BraceWrapping.SplitEmptyFunctionBody = false;
|
||||
Style.ColumnLimit = 40;
|
||||
|
||||
verifyFormat("int f()\n"
|
||||
"{}",
|
||||
Style);
|
||||
verifyFormat("int f()\n"
|
||||
"{\n"
|
||||
" return 42;\n"
|
||||
"}",
|
||||
Style);
|
||||
verifyFormat("int f()\n"
|
||||
"{\n"
|
||||
" // some comment\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
|
||||
verifyFormat("int f() {}", Style);
|
||||
verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
|
||||
"{}",
|
||||
Style);
|
||||
verifyFormat("int f()\n"
|
||||
"{\n"
|
||||
" return 0;\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
|
||||
verifyFormat("class Foo {\n"
|
||||
" int f() {}\n"
|
||||
"};\n",
|
||||
Style);
|
||||
verifyFormat("class Foo {\n"
|
||||
" int f() { return 0; }\n"
|
||||
"};\n",
|
||||
Style);
|
||||
verifyFormat("class Foo {\n"
|
||||
" int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
|
||||
" {}\n"
|
||||
"};\n",
|
||||
Style);
|
||||
verifyFormat("class Foo {\n"
|
||||
" int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
|
||||
" {\n"
|
||||
" return 0;\n"
|
||||
" }\n"
|
||||
"};\n",
|
||||
Style);
|
||||
|
||||
Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
|
||||
verifyFormat("int f() {}", Style);
|
||||
verifyFormat("int f() { return 0; }", Style);
|
||||
verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
|
||||
"{}",
|
||||
Style);
|
||||
verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
|
||||
"{\n"
|
||||
" return 0;\n"
|
||||
"}",
|
||||
Style);
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
|
||||
@ -8927,6 +9186,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
|
||||
CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
|
||||
CHECK_PARSE_BOOL(BreakStringLiterals);
|
||||
CHECK_PARSE_BOOL(BreakBeforeInheritanceComma)
|
||||
CHECK_PARSE_BOOL(CompactNamespaces);
|
||||
CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine);
|
||||
CHECK_PARSE_BOOL(DerivePointerAlignment);
|
||||
CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding");
|
||||
@ -8960,6 +9220,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
|
||||
CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeCatch);
|
||||
CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeElse);
|
||||
CHECK_PARSE_NESTED_BOOL(BraceWrapping, IndentBraces);
|
||||
CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyFunctionBody);
|
||||
}
|
||||
|
||||
#undef CHECK_PARSE_BOOL
|
||||
|
@ -185,6 +185,41 @@ TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) {
|
||||
"}\n"
|
||||
"}"));
|
||||
|
||||
// Add comment for namespaces which will be 'compacted'
|
||||
FormatStyle CompactNamespacesStyle = getLLVMStyle();
|
||||
CompactNamespacesStyle.CompactNamespaces = true;
|
||||
EXPECT_EQ("namespace out { namespace in {\n"
|
||||
"int i;\n"
|
||||
"int j;\n"
|
||||
"}}// namespace out::in",
|
||||
fixNamespaceEndComments("namespace out { namespace in {\n"
|
||||
"int i;\n"
|
||||
"int j;\n"
|
||||
"}}",
|
||||
CompactNamespacesStyle));
|
||||
EXPECT_EQ("namespace out {\n"
|
||||
"namespace in {\n"
|
||||
"int i;\n"
|
||||
"int j;\n"
|
||||
"}\n"
|
||||
"}// namespace out::in",
|
||||
fixNamespaceEndComments("namespace out {\n"
|
||||
"namespace in {\n"
|
||||
"int i;\n"
|
||||
"int j;\n"
|
||||
"}\n"
|
||||
"}",
|
||||
CompactNamespacesStyle));
|
||||
EXPECT_EQ("namespace out { namespace in {\n"
|
||||
"int i;\n"
|
||||
"int j;\n"
|
||||
"};}// namespace out::in",
|
||||
fixNamespaceEndComments("namespace out { namespace in {\n"
|
||||
"int i;\n"
|
||||
"int j;\n"
|
||||
"};}",
|
||||
CompactNamespacesStyle));
|
||||
|
||||
// Adds an end comment after a semicolon.
|
||||
EXPECT_EQ("namespace {\n"
|
||||
" int i;\n"
|
||||
@ -388,6 +423,27 @@ TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndLineComment) {
|
||||
fixNamespaceEndComments("namespace A {} // namespace"));
|
||||
EXPECT_EQ("namespace A {}; // namespace A",
|
||||
fixNamespaceEndComments("namespace A {}; // namespace"));
|
||||
|
||||
// Update invalid comments for compacted namespaces.
|
||||
FormatStyle CompactNamespacesStyle = getLLVMStyle();
|
||||
CompactNamespacesStyle.CompactNamespaces = true;
|
||||
EXPECT_EQ("namespace out { namespace in {\n"
|
||||
"}} // namespace out::in",
|
||||
fixNamespaceEndComments("namespace out { namespace in {\n"
|
||||
"}} // namespace out",
|
||||
CompactNamespacesStyle));
|
||||
EXPECT_EQ("namespace out { namespace in {\n"
|
||||
"}} // namespace out::in",
|
||||
fixNamespaceEndComments("namespace out { namespace in {\n"
|
||||
"}} // namespace in",
|
||||
CompactNamespacesStyle));
|
||||
EXPECT_EQ("namespace out { namespace in {\n"
|
||||
"}\n"
|
||||
"} // namespace out::in",
|
||||
fixNamespaceEndComments("namespace out { namespace in {\n"
|
||||
"}// banamespace in\n"
|
||||
"} // namespace out",
|
||||
CompactNamespacesStyle));
|
||||
}
|
||||
|
||||
TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndBlockComment) {
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include "clang/Basic/TargetOptions.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Lex/HeaderSearchOptions.h"
|
||||
#include "clang/Lex/MacroArgs.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/ModuleLoader.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/PreprocessorOptions.h"
|
||||
@ -41,26 +43,33 @@ protected:
|
||||
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
|
||||
}
|
||||
|
||||
std::vector<Token> Lex(StringRef Source) {
|
||||
std::unique_ptr<Preprocessor> CreatePP(StringRef Source,
|
||||
TrivialModuleLoader &ModLoader) {
|
||||
std::unique_ptr<llvm::MemoryBuffer> Buf =
|
||||
llvm::MemoryBuffer::getMemBuffer(Source);
|
||||
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
|
||||
|
||||
TrivialModuleLoader ModLoader;
|
||||
MemoryBufferCache PCMCache;
|
||||
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
|
||||
Diags, LangOpts, Target.get());
|
||||
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
|
||||
SourceMgr, PCMCache, HeaderInfo, ModLoader,
|
||||
/*IILookup =*/nullptr,
|
||||
/*OwnsHeaderSearch =*/false);
|
||||
PP.Initialize(*Target);
|
||||
PP.EnterMainSourceFile();
|
||||
std::unique_ptr<Preprocessor> PP = llvm::make_unique<Preprocessor>(
|
||||
std::make_shared<PreprocessorOptions>(), Diags, LangOpts, SourceMgr,
|
||||
PCMCache, HeaderInfo, ModLoader,
|
||||
/*IILookup =*/nullptr,
|
||||
/*OwnsHeaderSearch =*/false);
|
||||
PP->Initialize(*Target);
|
||||
PP->EnterMainSourceFile();
|
||||
return PP;
|
||||
}
|
||||
|
||||
std::vector<Token> Lex(StringRef Source) {
|
||||
TrivialModuleLoader ModLoader;
|
||||
auto PP = CreatePP(Source, ModLoader);
|
||||
|
||||
std::vector<Token> toks;
|
||||
while (1) {
|
||||
Token tok;
|
||||
PP.Lex(tok);
|
||||
PP->Lex(tok);
|
||||
if (tok.is(tok::eof))
|
||||
break;
|
||||
toks.push_back(tok);
|
||||
@ -365,4 +374,50 @@ TEST_F(LexerTest, DontMergeMacroArgsFromDifferentMacroFiles) {
|
||||
EXPECT_EQ(SourceMgr.getFileIDSize(SourceMgr.getFileID(helper1ArgLoc)), 8U);
|
||||
}
|
||||
|
||||
TEST_F(LexerTest, DontOverallocateStringifyArgs) {
|
||||
TrivialModuleLoader ModLoader;
|
||||
auto PP = CreatePP("\"StrArg\", 5, 'C'", ModLoader);
|
||||
|
||||
llvm::BumpPtrAllocator Allocator;
|
||||
std::array<IdentifierInfo *, 3> ArgList;
|
||||
MacroInfo *MI = PP->AllocateMacroInfo({});
|
||||
MI->setIsFunctionLike();
|
||||
MI->setArgumentList(ArgList, Allocator);
|
||||
EXPECT_EQ(3u, MI->getNumArgs());
|
||||
EXPECT_TRUE(MI->isFunctionLike());
|
||||
|
||||
Token Eof;
|
||||
Eof.setKind(tok::eof);
|
||||
std::vector<Token> ArgTokens;
|
||||
while (1) {
|
||||
Token tok;
|
||||
PP->Lex(tok);
|
||||
if (tok.is(tok::eof)) {
|
||||
ArgTokens.push_back(Eof);
|
||||
break;
|
||||
}
|
||||
if (tok.is(tok::comma))
|
||||
ArgTokens.push_back(Eof);
|
||||
else
|
||||
ArgTokens.push_back(tok);
|
||||
}
|
||||
|
||||
auto MacroArgsDeleter = [&PP](MacroArgs *M) { M->destroy(*PP); };
|
||||
std::unique_ptr<MacroArgs, decltype(MacroArgsDeleter)> MA(
|
||||
MacroArgs::create(MI, ArgTokens, false, *PP), MacroArgsDeleter);
|
||||
Token Result = MA->getStringifiedArgument(0, *PP, {}, {});
|
||||
EXPECT_EQ(tok::string_literal, Result.getKind());
|
||||
EXPECT_STREQ("\"\\\"StrArg\\\"\"", Result.getLiteralData());
|
||||
Result = MA->getStringifiedArgument(1, *PP, {}, {});
|
||||
EXPECT_EQ(tok::string_literal, Result.getKind());
|
||||
EXPECT_STREQ("\"5\"", Result.getLiteralData());
|
||||
Result = MA->getStringifiedArgument(2, *PP, {}, {});
|
||||
EXPECT_EQ(tok::string_literal, Result.getKind());
|
||||
EXPECT_STREQ("\"'C'\"", Result.getLiteralData());
|
||||
#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
|
||||
EXPECT_DEATH(MA->getStringifiedArgument(3, *PP, {}, {}),
|
||||
"Invalid argument number!");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
@ -143,8 +143,9 @@ TEST(LookupTest, replaceNestedClassName) {
|
||||
Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) {
|
||||
// Filter Types by name since there are other `RecordTypeLoc` in the test
|
||||
// file.
|
||||
if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo")
|
||||
if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
|
||||
EXPECT_EQ("x::Bar", replaceRecordTypeLoc(Type, "::a::x::Bar"));
|
||||
}
|
||||
};
|
||||
Visitor.runOver("namespace a { namespace b {\n"
|
||||
"class Foo;\n"
|
||||
@ -155,8 +156,9 @@ TEST(LookupTest, replaceNestedClassName) {
|
||||
// Filter Types by name since there are other `RecordTypeLoc` in the test
|
||||
// file.
|
||||
// `a::b::Foo` in using shadow decl is not `TypeLoc`.
|
||||
if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo")
|
||||
if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
|
||||
EXPECT_EQ("Bar", replaceRecordTypeLoc(Type, "::a::x::Bar"));
|
||||
}
|
||||
};
|
||||
Visitor.runOver("namespace a { namespace b { class Foo {}; } }\n"
|
||||
"namespace c { using a::b::Foo; Foo f();; }\n");
|
||||
|
Loading…
x
Reference in New Issue
Block a user