Vendor import of clang trunk r305575:

https://llvm.org/svn/llvm-project/cfe/trunk@305575
This commit is contained in:
Dimitry Andric 2017-06-16 21:03:44 +00:00
parent 1b08b196ac
commit 325377b573
91 changed files with 2244 additions and 406 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 = !{}

View File

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

View File

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

View 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'}}
};

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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