[clang] Revert parentesized aggregate initalization patches
This feature causes clang to crash when compiling Chrome - see https://crbug.com/1405031 and https://github.com/llvm/llvm-project/issues/59675 Revert "[clang] Fix a clang crash on invalid code in C++20 mode." This reverts commit 32d7aae04fdb58e65a952f281ff2f2c3f396d98f. Revert "[clang] Remove overly restrictive aggregate paren init logic" This reverts commit c77a91bb7ba793ec3a6a5da3743ed55056291658. Revert "[clang][C++20] P0960R3 and P1975R0: Allow initializing aggregates from a parenthesized list of values" This reverts commit 40c52159d3ee337dbed14e4c73b5616ea354c337.
This commit is contained in:
parent
45f347270c
commit
4e02ff2303
@ -714,10 +714,6 @@ C++20 Feature Support
|
||||
(useful specially for constrained members). Fixes `GH50886 <https://github.com/llvm/llvm-project/issues/50886>`_.
|
||||
- Implemented CWG2635 as a Defect Report, which prohibits structured bindings from being constrained.
|
||||
|
||||
- Implemented `P0960R3: <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0960r3.html>`_
|
||||
and `P1975R0: <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1975r0.html>`_,
|
||||
which allows parenthesized aggregate-initialization.
|
||||
|
||||
C++2b Feature Support
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@ -1531,13 +1531,7 @@ enum CXCursorKind {
|
||||
*/
|
||||
CXCursor_RequiresExpr = 154,
|
||||
|
||||
/**
|
||||
* Expression that references a C++20 parenthesized list aggregate
|
||||
* initializer.
|
||||
*/
|
||||
CXCursor_CXXParenListInitExpr = 155,
|
||||
|
||||
CXCursor_LastExpr = CXCursor_CXXParenListInitExpr,
|
||||
CXCursor_LastExpr = CXCursor_RequiresExpr,
|
||||
|
||||
/* Statements */
|
||||
CXCursor_FirstStmt = 200,
|
||||
|
||||
@ -710,12 +710,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void VisitCXXParenListInitExpr(const CXXParenListInitExpr *PLIE) {
|
||||
if (auto *Filler = PLIE->getArrayFiller()) {
|
||||
Visit(Filler, "array_filler");
|
||||
}
|
||||
}
|
||||
|
||||
void VisitBlockExpr(const BlockExpr *Node) { Visit(Node->getBlockDecl()); }
|
||||
|
||||
void VisitOpaqueValueExpr(const OpaqueValueExpr *Node) {
|
||||
|
||||
@ -79,7 +79,6 @@ class CXXUnresolvedConstructExpr;
|
||||
class CXXDependentScopeMemberExpr;
|
||||
class MaterializeTemporaryExpr;
|
||||
class CXXFoldExpr;
|
||||
class CXXParenListInitExpr;
|
||||
class TypeTraitExpr;
|
||||
class ConceptSpecializationExpr;
|
||||
class SYCLUniqueStableNameExpr;
|
||||
@ -169,7 +168,6 @@ ExprDependence computeDependence(CXXUnresolvedConstructExpr *E);
|
||||
ExprDependence computeDependence(CXXDependentScopeMemberExpr *E);
|
||||
ExprDependence computeDependence(MaterializeTemporaryExpr *E);
|
||||
ExprDependence computeDependence(CXXFoldExpr *E);
|
||||
ExprDependence computeDependence(CXXParenListInitExpr *E);
|
||||
ExprDependence computeDependence(TypeTraitExpr *E);
|
||||
ExprDependence computeDependence(ConceptSpecializationExpr *E,
|
||||
bool ValueDependent);
|
||||
|
||||
@ -914,10 +914,7 @@ public:
|
||||
CallInit,
|
||||
|
||||
/// Direct list-initialization (C++11)
|
||||
ListInit,
|
||||
|
||||
/// Parenthesized list-initialization (C++20)
|
||||
ParenListInit
|
||||
ListInit
|
||||
};
|
||||
|
||||
/// Kinds of thread-local storage.
|
||||
|
||||
@ -4713,130 +4713,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a list-initialization with parenthesis.
|
||||
///
|
||||
/// As per P0960R3, this is a C++20 feature that allows aggregate to
|
||||
/// be initialized with a parenthesized list of values:
|
||||
/// ```
|
||||
/// struct A {
|
||||
/// int a;
|
||||
/// double b;
|
||||
/// };
|
||||
///
|
||||
/// void foo() {
|
||||
/// A a1(0); // Well-formed in C++20
|
||||
/// A a2(1.5, 1.0); // Well-formed in C++20
|
||||
/// }
|
||||
/// ```
|
||||
/// It has some sort of similiarity to braced
|
||||
/// list-initialization, with some differences such as
|
||||
/// it allows narrowing conversion whilst braced
|
||||
/// list-initialization doesn't.
|
||||
/// ```
|
||||
/// struct A {
|
||||
/// char a;
|
||||
/// };
|
||||
/// void foo() {
|
||||
/// A a(1.5); // Well-formed in C++20
|
||||
/// A b{1.5}; // Ill-formed !
|
||||
/// }
|
||||
/// ```
|
||||
class CXXParenListInitExpr final
|
||||
: public Expr,
|
||||
private llvm::TrailingObjects<CXXParenListInitExpr, Expr *> {
|
||||
friend class TrailingObjects;
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
|
||||
unsigned NumExprs;
|
||||
unsigned NumUserSpecifiedExprs;
|
||||
SourceLocation InitLoc, LParenLoc, RParenLoc;
|
||||
Expr *ArrayFiller = nullptr;
|
||||
|
||||
CXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
|
||||
unsigned NumUserSpecifiedExprs, SourceLocation InitLoc,
|
||||
SourceLocation LParenLoc, SourceLocation RParenLoc)
|
||||
: Expr(CXXParenListInitExprClass, T,
|
||||
T->isLValueReferenceType() ? VK_LValue
|
||||
: T->isRValueReferenceType() ? VK_XValue
|
||||
: VK_PRValue,
|
||||
OK_Ordinary),
|
||||
NumExprs(Args.size()), NumUserSpecifiedExprs(NumUserSpecifiedExprs),
|
||||
InitLoc(InitLoc), LParenLoc(LParenLoc), RParenLoc(RParenLoc) {
|
||||
std::copy(Args.begin(), Args.end(), getTrailingObjects<Expr *>());
|
||||
assert(NumExprs >= NumUserSpecifiedExprs &&
|
||||
"number of user specified inits is greater than the number of "
|
||||
"passed inits");
|
||||
setDependence(computeDependence(this));
|
||||
}
|
||||
|
||||
size_t numTrailingObjects(OverloadToken<Expr *>) const { return NumExprs; }
|
||||
|
||||
public:
|
||||
static CXXParenListInitExpr *
|
||||
Create(ASTContext &C, ArrayRef<Expr *> Args, QualType T,
|
||||
unsigned NumUserSpecifiedExprs, SourceLocation InitLoc,
|
||||
SourceLocation LParenLoc, SourceLocation RParenLoc);
|
||||
|
||||
static CXXParenListInitExpr *CreateEmpty(ASTContext &C, unsigned numExprs,
|
||||
EmptyShell Empty);
|
||||
|
||||
explicit CXXParenListInitExpr(EmptyShell Empty, unsigned NumExprs)
|
||||
: Expr(CXXParenListInitExprClass, Empty), NumExprs(NumExprs),
|
||||
NumUserSpecifiedExprs(0) {}
|
||||
|
||||
void updateDependence() { setDependence(computeDependence(this)); }
|
||||
|
||||
ArrayRef<Expr *> getInitExprs() {
|
||||
return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumExprs);
|
||||
}
|
||||
|
||||
const ArrayRef<Expr *> getInitExprs() const {
|
||||
return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumExprs);
|
||||
}
|
||||
|
||||
ArrayRef<Expr *> getUserSpecifiedInitExprs() {
|
||||
return llvm::makeArrayRef(getTrailingObjects<Expr *>(),
|
||||
NumUserSpecifiedExprs);
|
||||
}
|
||||
|
||||
const ArrayRef<Expr *> getUserSpecifiedInitExprs() const {
|
||||
return llvm::makeArrayRef(getTrailingObjects<Expr *>(),
|
||||
NumUserSpecifiedExprs);
|
||||
}
|
||||
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; }
|
||||
|
||||
SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }
|
||||
|
||||
SourceLocation getInitLoc() const LLVM_READONLY { return InitLoc; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getBeginLoc(), getEndLoc());
|
||||
}
|
||||
|
||||
void setArrayFiller(Expr *E) { ArrayFiller = E; }
|
||||
|
||||
Expr *getArrayFiller() { return ArrayFiller; }
|
||||
|
||||
const Expr *getArrayFiller() const { return ArrayFiller; }
|
||||
|
||||
child_range children() {
|
||||
Stmt **Begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>());
|
||||
return child_range(Begin, Begin + NumExprs);
|
||||
}
|
||||
|
||||
const_child_range children() const {
|
||||
Stmt *const *Begin =
|
||||
reinterpret_cast<Stmt *const *>(getTrailingObjects<Expr *>());
|
||||
return const_child_range(Begin, Begin + NumExprs);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXParenListInitExprClass;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents an expression that might suspend coroutine execution;
|
||||
/// either a co_await or co_yield expression.
|
||||
///
|
||||
|
||||
@ -2852,7 +2852,6 @@ DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
|
||||
DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
|
||||
DEF_TRAVERSE_STMT(CXXFoldExpr, {})
|
||||
DEF_TRAVERSE_STMT(AtomicExpr, {})
|
||||
DEF_TRAVERSE_STMT(CXXParenListInitExpr, {})
|
||||
|
||||
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {
|
||||
if (S->getLifetimeExtendedTemporaryDecl()) {
|
||||
|
||||
@ -2164,9 +2164,6 @@ def err_init_list_bad_dest_type : Error<
|
||||
def warn_cxx20_compat_aggregate_init_with_ctors : Warning<
|
||||
"aggregate initialization of type %0 with user-declared constructors "
|
||||
"is incompatible with C++20">, DefaultIgnore, InGroup<CXX20Compat>;
|
||||
def warn_cxx17_compat_aggregate_init_paren_list : Warning<
|
||||
"aggregate initialization of type %0 from a parenthesized list of values "
|
||||
"is a C++20 extension">, DefaultIgnore, InGroup<CXX20>;
|
||||
|
||||
def err_reference_bind_to_bitfield : Error<
|
||||
"%select{non-const|volatile}0 reference cannot bind to "
|
||||
|
||||
@ -160,7 +160,6 @@ def FunctionParmPackExpr : StmtNode<Expr>;
|
||||
def MaterializeTemporaryExpr : StmtNode<Expr>;
|
||||
def LambdaExpr : StmtNode<Expr>;
|
||||
def CXXFoldExpr : StmtNode<Expr>;
|
||||
def CXXParenListInitExpr: StmtNode<Expr>;
|
||||
|
||||
// C++ Coroutines TS expressions
|
||||
def CoroutineSuspendExpr : StmtNode<Expr, 1>;
|
||||
|
||||
@ -923,11 +923,7 @@ public:
|
||||
SK_OCLSamplerInit,
|
||||
|
||||
/// Initialize an opaque OpenCL type (event_t, queue_t, etc.) with zero
|
||||
SK_OCLZeroOpaqueType,
|
||||
|
||||
/// Initialize an aggreagate with parenthesized list of values.
|
||||
/// This is a C++20 feature.
|
||||
SK_ParenthesizedListInit
|
||||
SK_OCLZeroOpaqueType
|
||||
};
|
||||
|
||||
/// A single step in the initialization sequence.
|
||||
@ -1103,10 +1099,6 @@ public:
|
||||
|
||||
/// List-copy-initialization chose an explicit constructor.
|
||||
FK_ExplicitConstructor,
|
||||
|
||||
/// Parenthesized list initialization failed at some point.
|
||||
/// This is a C++20 feature.
|
||||
FK_ParenthesizedListInitFailed,
|
||||
};
|
||||
|
||||
private:
|
||||
@ -1365,8 +1357,6 @@ public:
|
||||
/// from a zero constant.
|
||||
void AddOCLZeroOpaqueTypeStep(QualType T);
|
||||
|
||||
void AddParenthesizedListInitStep(QualType T);
|
||||
|
||||
/// Add steps to unwrap a initializer list for a reference around a
|
||||
/// single element and rewrap it at the end.
|
||||
void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic);
|
||||
|
||||
@ -1861,9 +1861,6 @@ enum StmtCode {
|
||||
/// A CXXBoolLiteralExpr record.
|
||||
EXPR_CXX_BOOL_LITERAL,
|
||||
|
||||
/// A CXXParenListInitExpr record.
|
||||
EXPR_CXX_PAREN_LIST_INIT,
|
||||
|
||||
EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr
|
||||
EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr).
|
||||
EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type).
|
||||
|
||||
@ -831,13 +831,6 @@ ExprDependence clang::computeDependence(CXXFoldExpr *E) {
|
||||
return D;
|
||||
}
|
||||
|
||||
ExprDependence clang::computeDependence(CXXParenListInitExpr *E) {
|
||||
auto D = ExprDependence::None;
|
||||
for (const auto *A : E->getInitExprs())
|
||||
D |= A->getDependence();
|
||||
return D;
|
||||
}
|
||||
|
||||
ExprDependence clang::computeDependence(TypeTraitExpr *E) {
|
||||
auto D = ExprDependence::None;
|
||||
for (const auto *A : E->getArgs())
|
||||
|
||||
@ -3644,7 +3644,6 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
|
||||
case ShuffleVectorExprClass:
|
||||
case ConvertVectorExprClass:
|
||||
case AsTypeExprClass:
|
||||
case CXXParenListInitExprClass:
|
||||
// These have a side-effect if any subexpression does.
|
||||
break;
|
||||
|
||||
|
||||
@ -1757,21 +1757,3 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx,
|
||||
alignof(CUDAKernelCallExpr));
|
||||
return new (Mem) CUDAKernelCallExpr(NumArgs, HasFPFeatures, Empty);
|
||||
}
|
||||
|
||||
CXXParenListInitExpr *
|
||||
CXXParenListInitExpr::Create(ASTContext &C, ArrayRef<Expr *> Args, QualType T,
|
||||
unsigned NumUserSpecifiedExprs,
|
||||
SourceLocation InitLoc, SourceLocation LParenLoc,
|
||||
SourceLocation RParenLoc) {
|
||||
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(Args.size()));
|
||||
return new (Mem) CXXParenListInitExpr(Args, T, NumUserSpecifiedExprs, InitLoc,
|
||||
LParenLoc, RParenLoc);
|
||||
}
|
||||
|
||||
CXXParenListInitExpr *CXXParenListInitExpr::CreateEmpty(ASTContext &C,
|
||||
unsigned NumExprs,
|
||||
EmptyShell Empty) {
|
||||
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(NumExprs),
|
||||
alignof(CXXParenListInitExpr));
|
||||
return new (Mem) CXXParenListInitExpr(Empty, NumExprs);
|
||||
}
|
||||
|
||||
@ -445,11 +445,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
|
||||
case Expr::SYCLUniqueStableNameExprClass:
|
||||
return Cl::CL_PRValue;
|
||||
break;
|
||||
|
||||
case Expr::CXXParenListInitExprClass:
|
||||
if (isa<ArrayType>(E->getType()))
|
||||
return Cl::CL_ArrayTemporary;
|
||||
return Cl::CL_ClassTemporary;
|
||||
}
|
||||
|
||||
llvm_unreachable("unhandled expression kind in classification");
|
||||
|
||||
@ -9836,9 +9836,6 @@ namespace {
|
||||
bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
|
||||
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
|
||||
bool VisitBinCmp(const BinaryOperator *E);
|
||||
bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
|
||||
bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
|
||||
ArrayRef<Expr *> Args);
|
||||
};
|
||||
}
|
||||
|
||||
@ -9957,13 +9954,8 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||
bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
|
||||
if (E->isTransparent())
|
||||
return Visit(E->getInit(0));
|
||||
return VisitCXXParenListOrInitListExpr(E, E->inits());
|
||||
}
|
||||
|
||||
bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
|
||||
const Expr *ExprToVisit, ArrayRef<Expr *> Args) {
|
||||
const RecordDecl *RD =
|
||||
ExprToVisit->getType()->castAs<RecordType>()->getDecl();
|
||||
const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
|
||||
if (RD->isInvalidDecl()) return false;
|
||||
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
|
||||
auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
|
||||
@ -9974,25 +9966,7 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
|
||||
CXXRD && CXXRD->getNumBases());
|
||||
|
||||
if (RD->isUnion()) {
|
||||
const FieldDecl *Field;
|
||||
if (auto *ILE = dyn_cast<InitListExpr>(ExprToVisit)) {
|
||||
Field = ILE->getInitializedFieldInUnion();
|
||||
} else if (isa<CXXParenListInitExpr>(ExprToVisit)) {
|
||||
assert(Args.size() == 1 &&
|
||||
"Unions should have exactly 1 initializer in a C++ paren list");
|
||||
|
||||
for (const FieldDecl *FD : RD->fields()) {
|
||||
if (FD->isUnnamedBitfield())
|
||||
continue;
|
||||
|
||||
Field = FD;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
llvm_unreachable(
|
||||
"Expression is neither an init list nor a C++ paren list");
|
||||
}
|
||||
|
||||
const FieldDecl *Field = E->getInitializedFieldInUnion();
|
||||
Result = APValue(Field);
|
||||
if (!Field)
|
||||
return true;
|
||||
@ -10003,7 +9977,7 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
|
||||
// Is this difference ever observable for initializer lists which
|
||||
// we don't build?
|
||||
ImplicitValueInitExpr VIE(Field->getType());
|
||||
const Expr *InitExpr = Args.empty() ? &VIE : Args[0];
|
||||
const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE;
|
||||
|
||||
LValue Subobject = This;
|
||||
if (!HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout))
|
||||
@ -10032,8 +10006,8 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
|
||||
// Initialize base classes.
|
||||
if (CXXRD && CXXRD->getNumBases()) {
|
||||
for (const auto &Base : CXXRD->bases()) {
|
||||
assert(ElementNo < Args.size() && "missing init for base class");
|
||||
const Expr *Init = Args[ElementNo];
|
||||
assert(ElementNo < E->getNumInits() && "missing init for base class");
|
||||
const Expr *Init = E->getInit(ElementNo);
|
||||
|
||||
LValue Subobject = This;
|
||||
if (!HandleLValueBase(Info, Init, Subobject, CXXRD, &Base))
|
||||
@ -10060,18 +10034,18 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
|
||||
|
||||
LValue Subobject = This;
|
||||
|
||||
bool HaveInit = ElementNo < Args.size();
|
||||
bool HaveInit = ElementNo < E->getNumInits();
|
||||
|
||||
// FIXME: Diagnostics here should point to the end of the initializer
|
||||
// list, not the start.
|
||||
if (!HandleLValueMember(Info, HaveInit ? Args[ElementNo] : ExprToVisit,
|
||||
if (!HandleLValueMember(Info, HaveInit ? E->getInit(ElementNo) : E,
|
||||
Subobject, Field, &Layout))
|
||||
return false;
|
||||
|
||||
// Perform an implicit value-initialization for members beyond the end of
|
||||
// the initializer list.
|
||||
ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType());
|
||||
const Expr *Init = HaveInit ? Args[ElementNo++] : &VIE;
|
||||
const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE;
|
||||
|
||||
if (Field->getType()->isIncompleteArrayType()) {
|
||||
if (auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType())) {
|
||||
@ -10705,11 +10679,6 @@ namespace {
|
||||
expandStringLiteral(Info, E, Result, AllocType);
|
||||
return true;
|
||||
}
|
||||
bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
|
||||
bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
|
||||
ArrayRef<Expr *> Args,
|
||||
const Expr *ArrayFiller,
|
||||
QualType AllocType = QualType());
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
@ -10785,16 +10754,6 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
|
||||
assert(!E->isTransparent() &&
|
||||
"transparent array list initialization is not string literal init?");
|
||||
|
||||
return VisitCXXParenListOrInitListExpr(E, E->inits(), E->getArrayFiller(),
|
||||
AllocType);
|
||||
}
|
||||
|
||||
bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr(
|
||||
const Expr *ExprToVisit, ArrayRef<Expr *> Args, const Expr *ArrayFiller,
|
||||
QualType AllocType) {
|
||||
const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(
|
||||
AllocType.isNull() ? ExprToVisit->getType() : AllocType);
|
||||
|
||||
bool Success = true;
|
||||
|
||||
assert((!Result.isArray() || Result.getArrayInitializedElts() == 0) &&
|
||||
@ -10803,12 +10762,13 @@ bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr(
|
||||
if (Result.isArray() && Result.hasArrayFiller())
|
||||
Filler = Result.getArrayFiller();
|
||||
|
||||
unsigned NumEltsToInit = Args.size();
|
||||
unsigned NumEltsToInit = E->getNumInits();
|
||||
unsigned NumElts = CAT->getSize().getZExtValue();
|
||||
const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : nullptr;
|
||||
|
||||
// If the initializer might depend on the array index, run it for each
|
||||
// array element.
|
||||
if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(ArrayFiller))
|
||||
if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(FillerExpr))
|
||||
NumEltsToInit = NumElts;
|
||||
|
||||
LLVM_DEBUG(llvm::dbgs() << "The number of elements to initialize: "
|
||||
@ -10826,9 +10786,10 @@ bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr(
|
||||
}
|
||||
|
||||
LValue Subobject = This;
|
||||
Subobject.addArray(Info, ExprToVisit, CAT);
|
||||
Subobject.addArray(Info, E, CAT);
|
||||
for (unsigned Index = 0; Index != NumEltsToInit; ++Index) {
|
||||
const Expr *Init = Index < Args.size() ? Args[Index] : ArrayFiller;
|
||||
const Expr *Init =
|
||||
Index < E->getNumInits() ? E->getInit(Index) : FillerExpr;
|
||||
if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
|
||||
Info, Subobject, Init) ||
|
||||
!HandleLValueArrayAdjustment(Info, Init, Subobject,
|
||||
@ -10844,10 +10805,9 @@ bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr(
|
||||
|
||||
// If we get here, we have a trivial filler, which we can just evaluate
|
||||
// once and splat over the rest of the array elements.
|
||||
assert(ArrayFiller && "no array filler for incomplete init list");
|
||||
assert(FillerExpr && "no array filler for incomplete init list");
|
||||
return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject,
|
||||
ArrayFiller) &&
|
||||
Success;
|
||||
FillerExpr) && Success;
|
||||
}
|
||||
|
||||
bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
|
||||
@ -10964,15 +10924,6 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
|
||||
.VisitCXXConstructExpr(E, Type);
|
||||
}
|
||||
|
||||
bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
|
||||
const CXXParenListInitExpr *E) {
|
||||
assert(dyn_cast<ConstantArrayType>(E->getType()) &&
|
||||
"Expression result is not a constant array type");
|
||||
|
||||
return VisitCXXParenListOrInitListExpr(E, E->getInitExprs(),
|
||||
E->getArrayFiller());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Integer Evaluation
|
||||
//
|
||||
@ -13234,11 +13185,6 @@ bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) {
|
||||
});
|
||||
}
|
||||
|
||||
bool RecordExprEvaluator::VisitCXXParenListInitExpr(
|
||||
const CXXParenListInitExpr *E) {
|
||||
return VisitCXXParenListOrInitListExpr(E, E->getInitExprs());
|
||||
}
|
||||
|
||||
bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
|
||||
// We don't support assignment in C. C++ assignments don't get here because
|
||||
// assignment is an lvalue in C++.
|
||||
@ -15682,7 +15628,6 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
|
||||
case Expr::DependentCoawaitExprClass:
|
||||
case Expr::CoyieldExprClass:
|
||||
case Expr::SYCLUniqueStableNameExprClass:
|
||||
case Expr::CXXParenListInitExprClass:
|
||||
return ICEDiag(IK_NotICE, E->getBeginLoc());
|
||||
|
||||
case Expr::InitListExprClass: {
|
||||
|
||||
@ -4249,7 +4249,6 @@ recurse:
|
||||
case Expr::OMPArrayShapingExprClass:
|
||||
case Expr::OMPIteratorExprClass:
|
||||
case Expr::CXXInheritedCtorInitExprClass:
|
||||
case Expr::CXXParenListInitExprClass:
|
||||
llvm_unreachable("unexpected statement kind");
|
||||
|
||||
case Expr::ConstantExprClass:
|
||||
|
||||
@ -850,9 +850,6 @@ void JSONNodeDumper::VisitVarDecl(const VarDecl *VD) {
|
||||
case VarDecl::CInit: JOS.attribute("init", "c"); break;
|
||||
case VarDecl::CallInit: JOS.attribute("init", "call"); break;
|
||||
case VarDecl::ListInit: JOS.attribute("init", "list"); break;
|
||||
case VarDecl::ParenListInit:
|
||||
JOS.attribute("init", "paren-list");
|
||||
break;
|
||||
}
|
||||
}
|
||||
attributeOnlyIfTrue("isParameterPack", VD->isParameterPack());
|
||||
|
||||
@ -2465,13 +2465,6 @@ void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) {
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCXXParenListInitExpr(CXXParenListInitExpr *Node) {
|
||||
OS << "(";
|
||||
llvm::interleaveComma(Node->getInitExprs(), OS,
|
||||
[&](Expr *E) { PrintExpr(E); });
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
|
||||
NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc();
|
||||
if (NNS)
|
||||
|
||||
@ -2193,10 +2193,6 @@ void StmtProfiler::VisitCXXFoldExpr(const CXXFoldExpr *S) {
|
||||
ID.AddInteger(S->getOperator());
|
||||
}
|
||||
|
||||
void StmtProfiler::VisitCXXParenListInitExpr(const CXXParenListInitExpr *S) {
|
||||
VisitExpr(S);
|
||||
}
|
||||
|
||||
void StmtProfiler::VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
|
||||
VisitStmt(S);
|
||||
}
|
||||
|
||||
@ -1806,8 +1806,6 @@ void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
|
||||
case VarDecl::ListInit:
|
||||
OS << " listinit";
|
||||
break;
|
||||
case VarDecl::ParenListInit:
|
||||
OS << " parenlistinit";
|
||||
}
|
||||
}
|
||||
if (D->needsDestruction(D->getASTContext()))
|
||||
|
||||
@ -87,9 +87,8 @@ public:
|
||||
|
||||
void EmitMoveFromReturnSlot(const Expr *E, RValue Src);
|
||||
|
||||
void EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, QualType ArrayQTy,
|
||||
Expr *ExprToVisit, ArrayRef<Expr *> Args,
|
||||
Expr *ArrayFiller);
|
||||
void EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
|
||||
QualType ArrayQTy, InitListExpr *E);
|
||||
|
||||
AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) {
|
||||
if (CGF.getLangOpts().getGC() && TypeRequiresGCollection(T))
|
||||
@ -173,9 +172,6 @@ public:
|
||||
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
|
||||
void VisitChooseExpr(const ChooseExpr *CE);
|
||||
void VisitInitListExpr(InitListExpr *E);
|
||||
void VisitCXXParenListOrInitListExpr(Expr *ExprToVisit, ArrayRef<Expr *> Args,
|
||||
FieldDecl *InitializedFieldInUnion,
|
||||
Expr *ArrayFiller);
|
||||
void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
|
||||
llvm::Value *outerBegin = nullptr);
|
||||
void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
|
||||
@ -209,9 +205,6 @@ public:
|
||||
}
|
||||
|
||||
void VisitVAArgExpr(VAArgExpr *E);
|
||||
void VisitCXXParenListInitExpr(CXXParenListInitExpr *E);
|
||||
void VisitCXXParenListOrInitListExpr(Expr *ExprToVisit, ArrayRef<Expr *> Args,
|
||||
Expr *ArrayFiller);
|
||||
|
||||
void EmitInitializationToLValue(Expr *E, LValue Address);
|
||||
void EmitNullInitializationToLValue(LValue Address);
|
||||
@ -478,12 +471,10 @@ static bool isTrivialFiller(Expr *E) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Emit initialization of an array from an initializer list. ExprToVisit must
|
||||
/// be either an InitListEpxr a CXXParenInitListExpr.
|
||||
/// Emit initialization of an array from an initializer list.
|
||||
void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
|
||||
QualType ArrayQTy, Expr *ExprToVisit,
|
||||
ArrayRef<Expr *> Args, Expr *ArrayFiller) {
|
||||
uint64_t NumInitElements = Args.size();
|
||||
QualType ArrayQTy, InitListExpr *E) {
|
||||
uint64_t NumInitElements = E->getNumInits();
|
||||
|
||||
uint64_t NumArrayElements = AType->getNumElements();
|
||||
assert(NumInitElements <= NumArrayElements);
|
||||
@ -512,8 +503,7 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
|
||||
CodeGen::CodeGenModule &CGM = CGF.CGM;
|
||||
ConstantEmitter Emitter(CGF);
|
||||
LangAS AS = ArrayQTy.getAddressSpace();
|
||||
if (llvm::Constant *C =
|
||||
Emitter.tryEmitForInitializer(ExprToVisit, AS, ArrayQTy)) {
|
||||
if (llvm::Constant *C = Emitter.tryEmitForInitializer(E, AS, ArrayQTy)) {
|
||||
auto GV = new llvm::GlobalVariable(
|
||||
CGM.getModule(), C->getType(),
|
||||
CGM.isTypeConstant(ArrayQTy, /* ExcludeCtorDtor= */ true),
|
||||
@ -578,11 +568,12 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
|
||||
|
||||
LValue elementLV = CGF.MakeAddrLValue(
|
||||
Address(element, llvmElementType, elementAlign), elementType);
|
||||
EmitInitializationToLValue(Args[i], elementLV);
|
||||
EmitInitializationToLValue(E->getInit(i), elementLV);
|
||||
}
|
||||
|
||||
// Check whether there's a non-trivial array-fill expression.
|
||||
bool hasTrivialFiller = isTrivialFiller(ArrayFiller);
|
||||
Expr *filler = E->getArrayFiller();
|
||||
bool hasTrivialFiller = isTrivialFiller(filler);
|
||||
|
||||
// Any remaining elements need to be zero-initialized, possibly
|
||||
// using the filler expression. We can skip this if the we're
|
||||
@ -625,8 +616,8 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
|
||||
CodeGenFunction::RunCleanupsScope CleanupsScope(CGF);
|
||||
LValue elementLV = CGF.MakeAddrLValue(
|
||||
Address(currentElement, llvmElementType, elementAlign), elementType);
|
||||
if (ArrayFiller)
|
||||
EmitInitializationToLValue(ArrayFiller, elementLV);
|
||||
if (filler)
|
||||
EmitInitializationToLValue(filler, elementLV);
|
||||
else
|
||||
EmitNullInitializationToLValue(elementLV);
|
||||
}
|
||||
@ -1600,76 +1591,46 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
|
||||
}
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
|
||||
ArrayRef<Expr *> InitExprs = E->getInitExprs();
|
||||
FieldDecl *InitializedFieldInUnion = nullptr;
|
||||
if (E->getType()->isUnionType()) {
|
||||
auto *RD =
|
||||
dyn_cast<CXXRecordDecl>(E->getType()->castAs<RecordType>()->getDecl());
|
||||
for (FieldDecl *FD : RD->fields()) {
|
||||
if (FD->isUnnamedBitfield())
|
||||
continue;
|
||||
InitializedFieldInUnion = FD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VisitCXXParenListOrInitListExpr(E, InitExprs, InitializedFieldInUnion,
|
||||
E->getArrayFiller());
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
|
||||
if (E->hadArrayRangeDesignator())
|
||||
CGF.ErrorUnsupported(E, "GNU array range designator extension");
|
||||
|
||||
if (E->isTransparent())
|
||||
return Visit(E->getInit(0));
|
||||
|
||||
VisitCXXParenListOrInitListExpr(
|
||||
E, E->inits(), E->getInitializedFieldInUnion(), E->getArrayFiller());
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitCXXParenListOrInitListExpr(
|
||||
Expr *ExprToVisit, ArrayRef<Expr *> InitExprs,
|
||||
FieldDecl *InitializedFieldInUnion, Expr *ArrayFiller) {
|
||||
#if 0
|
||||
// FIXME: Assess perf here? Figure out what cases are worth optimizing here
|
||||
// (Length of globals? Chunks of zeroed-out space?).
|
||||
//
|
||||
// If we can, prefer a copy from a global; this is a lot less code for long
|
||||
// globals, and it's easier for the current optimizers to analyze.
|
||||
if (llvm::Constant *C =
|
||||
CGF.CGM.EmitConstantExpr(ExprToVisit, ExprToVisit->getType(), &CGF)) {
|
||||
if (llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, E->getType(), &CGF)) {
|
||||
llvm::GlobalVariable* GV =
|
||||
new llvm::GlobalVariable(CGF.CGM.getModule(), C->getType(), true,
|
||||
llvm::GlobalValue::InternalLinkage, C, "");
|
||||
EmitFinalDestCopy(ExprToVisit->getType(),
|
||||
CGF.MakeAddrLValue(GV, ExprToVisit->getType()));
|
||||
EmitFinalDestCopy(E->getType(), CGF.MakeAddrLValue(GV, E->getType()));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (E->hadArrayRangeDesignator())
|
||||
CGF.ErrorUnsupported(E, "GNU array range designator extension");
|
||||
|
||||
AggValueSlot Dest = EnsureSlot(ExprToVisit->getType());
|
||||
if (E->isTransparent())
|
||||
return Visit(E->getInit(0));
|
||||
|
||||
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), ExprToVisit->getType());
|
||||
AggValueSlot Dest = EnsureSlot(E->getType());
|
||||
|
||||
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
|
||||
|
||||
// Handle initialization of an array.
|
||||
if (ExprToVisit->getType()->isArrayType()) {
|
||||
if (E->getType()->isArrayType()) {
|
||||
auto AType = cast<llvm::ArrayType>(Dest.getAddress().getElementType());
|
||||
EmitArrayInit(Dest.getAddress(), AType, ExprToVisit->getType(), ExprToVisit,
|
||||
InitExprs, ArrayFiller);
|
||||
EmitArrayInit(Dest.getAddress(), AType, E->getType(), E);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(ExprToVisit->getType()->isRecordType() &&
|
||||
"Only support structs/unions here!");
|
||||
assert(E->getType()->isRecordType() && "Only support structs/unions here!");
|
||||
|
||||
// Do struct initialization; this code just sets each individual member
|
||||
// to the approprate value. This makes bitfield support automatic;
|
||||
// the disadvantage is that the generated code is more difficult for
|
||||
// the optimizer, especially with bitfields.
|
||||
unsigned NumInitElements = InitExprs.size();
|
||||
RecordDecl *record = ExprToVisit->getType()->castAs<RecordType>()->getDecl();
|
||||
unsigned NumInitElements = E->getNumInits();
|
||||
RecordDecl *record = E->getType()->castAs<RecordType>()->getDecl();
|
||||
|
||||
// We'll need to enter cleanup scopes in case any of the element
|
||||
// initializers throws an exception.
|
||||
@ -1687,7 +1648,7 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
|
||||
|
||||
// Emit initialization of base classes.
|
||||
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(record)) {
|
||||
assert(NumInitElements >= CXXRD->getNumBases() &&
|
||||
assert(E->getNumInits() >= CXXRD->getNumBases() &&
|
||||
"missing initializer for base class");
|
||||
for (auto &Base : CXXRD->bases()) {
|
||||
assert(!Base.isVirtual() && "should not see vbases here");
|
||||
@ -1701,7 +1662,7 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
|
||||
AggValueSlot::DoesNotNeedGCBarriers,
|
||||
AggValueSlot::IsNotAliased,
|
||||
CGF.getOverlapForBaseInit(CXXRD, BaseRD, Base.isVirtual()));
|
||||
CGF.EmitAggExpr(InitExprs[curInitIndex++], AggSlot);
|
||||
CGF.EmitAggExpr(E->getInit(curInitIndex++), AggSlot);
|
||||
|
||||
if (QualType::DestructionKind dtorKind =
|
||||
Base.getType().isDestructedType()) {
|
||||
@ -1717,7 +1678,7 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
|
||||
if (record->isUnion()) {
|
||||
// Only initialize one field of a union. The field itself is
|
||||
// specified by the initializer list.
|
||||
if (!InitializedFieldInUnion) {
|
||||
if (!E->getInitializedFieldInUnion()) {
|
||||
// Empty union; we have nothing to do.
|
||||
|
||||
#ifndef NDEBUG
|
||||
@ -1730,12 +1691,12 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
|
||||
}
|
||||
|
||||
// FIXME: volatility
|
||||
FieldDecl *Field = InitializedFieldInUnion;
|
||||
FieldDecl *Field = E->getInitializedFieldInUnion();
|
||||
|
||||
LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestLV, Field);
|
||||
if (NumInitElements) {
|
||||
// Store the initializer into the field
|
||||
EmitInitializationToLValue(InitExprs[0], FieldLoc);
|
||||
EmitInitializationToLValue(E->getInit(0), FieldLoc);
|
||||
} else {
|
||||
// Default-initialize to null.
|
||||
EmitNullInitializationToLValue(FieldLoc);
|
||||
@ -1759,7 +1720,7 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
|
||||
// have a zeroed object, and the rest of the fields are
|
||||
// zero-initializable.
|
||||
if (curInitIndex == NumInitElements && Dest.isZeroed() &&
|
||||
CGF.getTypes().isZeroInitializable(ExprToVisit->getType()))
|
||||
CGF.getTypes().isZeroInitializable(E->getType()))
|
||||
break;
|
||||
|
||||
|
||||
@ -1769,7 +1730,7 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
|
||||
|
||||
if (curInitIndex < NumInitElements) {
|
||||
// Store the initializer into the field.
|
||||
EmitInitializationToLValue(InitExprs[curInitIndex++], LV);
|
||||
EmitInitializationToLValue(E->getInit(curInitIndex++), LV);
|
||||
} else {
|
||||
// We're out of initializers; default-initialize to null
|
||||
EmitNullInitializationToLValue(LV);
|
||||
|
||||
@ -674,7 +674,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
|
||||
|
||||
// C++20 features.
|
||||
if (LangOpts.CPlusPlus20) {
|
||||
Builder.defineMacro("__cpp_aggregate_paren_init", "201902L");
|
||||
// Builder.defineMacro("__cpp_aggregate_paren_init", "201902L");
|
||||
|
||||
// P0848 is implemented, but we're still waiting for other concepts
|
||||
// issues to be addressed before bumping __cpp_concepts up to 202002L.
|
||||
|
||||
@ -451,7 +451,6 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
|
||||
|
||||
case InitializationSequence::FK_ConstructorOverloadFailed:
|
||||
case InitializationSequence::FK_UserConversionOverloadFailed:
|
||||
case InitializationSequence::FK_ParenthesizedListInitFailed:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -13145,7 +13145,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
||||
|
||||
// Perform the initialization.
|
||||
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
|
||||
bool IsParenListInit = false;
|
||||
if (!VDecl->isInvalidDecl()) {
|
||||
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
|
||||
InitializationKind Kind = InitializationKind::CreateForInit(
|
||||
@ -13188,9 +13187,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
||||
}
|
||||
|
||||
Init = Result.getAs<Expr>();
|
||||
IsParenListInit = !InitSeq.steps().empty() &&
|
||||
InitSeq.step_begin()->Kind ==
|
||||
InitializationSequence::SK_ParenthesizedListInit;
|
||||
}
|
||||
|
||||
// Check for self-references within variable initializers.
|
||||
@ -13439,8 +13435,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
||||
// class type.
|
||||
if (CXXDirectInit) {
|
||||
assert(DirectInit && "Call-style initializer must be direct init.");
|
||||
VDecl->setInitStyle(IsParenListInit ? VarDecl::ParenListInit
|
||||
: VarDecl::CallInit);
|
||||
VDecl->setInitStyle(VarDecl::CallInit);
|
||||
} else if (DirectInit) {
|
||||
// This must be list-initialization. No other way is direct-initialization.
|
||||
VDecl->setInitStyle(VarDecl::ListInit);
|
||||
|
||||
@ -1289,7 +1289,6 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
|
||||
case Expr::StmtExprClass:
|
||||
case Expr::ConvertVectorExprClass:
|
||||
case Expr::VAArgExprClass:
|
||||
case Expr::CXXParenListInitExprClass:
|
||||
return canSubStmtsThrow(*this, S);
|
||||
|
||||
case Expr::CompoundLiteralExprClass:
|
||||
|
||||
@ -3529,7 +3529,6 @@ void InitializationSequence::Step::Destroy() {
|
||||
case SK_StdInitializerListConstructorCall:
|
||||
case SK_OCLSamplerInit:
|
||||
case SK_OCLZeroOpaqueType:
|
||||
case SK_ParenthesizedListInit:
|
||||
break;
|
||||
|
||||
case SK_ConversionSequence:
|
||||
@ -3589,7 +3588,6 @@ bool InitializationSequence::isAmbiguous() const {
|
||||
case FK_PlaceholderType:
|
||||
case FK_ExplicitConstructor:
|
||||
case FK_AddressOfUnaddressableFunction:
|
||||
case FK_ParenthesizedListInitFailed:
|
||||
return false;
|
||||
|
||||
case FK_ReferenceInitOverloadFailed:
|
||||
@ -3825,13 +3823,6 @@ void InitializationSequence::AddOCLZeroOpaqueTypeStep(QualType T) {
|
||||
Steps.push_back(S);
|
||||
}
|
||||
|
||||
void InitializationSequence::AddParenthesizedListInitStep(QualType T) {
|
||||
Step S;
|
||||
S.Kind = SK_ParenthesizedListInit;
|
||||
S.Type = T;
|
||||
Steps.push_back(S);
|
||||
}
|
||||
|
||||
void InitializationSequence::RewrapReferenceInitList(QualType T,
|
||||
InitListExpr *Syntactic) {
|
||||
assert(Syntactic->getNumInits() == 1 &&
|
||||
@ -5269,198 +5260,6 @@ static void TryDefaultInitialization(Sema &S,
|
||||
}
|
||||
}
|
||||
|
||||
static void TryOrBuildParenListInitialization(
|
||||
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
|
||||
ArrayRef<Expr *> Args, InitializationSequence &Sequence, bool VerifyOnly,
|
||||
ExprResult *Result = nullptr) {
|
||||
unsigned ArgIndexToProcess = 0;
|
||||
SmallVector<Expr *, 4> InitExprs;
|
||||
QualType ResultType;
|
||||
Expr *ArrayFiller = nullptr;
|
||||
|
||||
// Process entities (i.e. array members, base classes, or class fields) by
|
||||
// adding an initialization expression to InitExprs for each entity to
|
||||
// initialize.
|
||||
auto ProcessEntities = [&](auto Range) -> bool {
|
||||
for (InitializedEntity SubEntity : Range) {
|
||||
// Unions should only have one initializer expression.
|
||||
// If there are more initializers than it will be caught when we check
|
||||
// whether Index equals Args.size().
|
||||
if (ArgIndexToProcess == 1 && Entity.getType()->isUnionType())
|
||||
return true;
|
||||
|
||||
// Unnamed bitfields should not be initialized at all, either with an arg
|
||||
// or by default.
|
||||
if (SubEntity.getKind() == InitializedEntity::EK_Member &&
|
||||
cast<FieldDecl>(SubEntity.getDecl())->isUnnamedBitfield())
|
||||
continue;
|
||||
|
||||
if (ArgIndexToProcess < Args.size()) {
|
||||
// There are still expressions in Args that haven't been processed.
|
||||
// Let's match them to the current entity to initialize.
|
||||
Expr *E = Args[ArgIndexToProcess++];
|
||||
|
||||
// Incomplete array types indicate flexible array members. Do not allow
|
||||
// paren list initializations of structs with these members, as GCC
|
||||
// doesn't either.
|
||||
if (SubEntity.getKind() == InitializedEntity::EK_Member) {
|
||||
auto *FD = cast<FieldDecl>(SubEntity.getDecl());
|
||||
if (FD->getType()->isIncompleteArrayType()) {
|
||||
if (!VerifyOnly) {
|
||||
S.Diag(E->getBeginLoc(), diag::err_flexible_array_init)
|
||||
<< SourceRange(E->getBeginLoc(), E->getEndLoc());
|
||||
S.Diag(FD->getLocation(), diag::note_flexible_array_member) << FD;
|
||||
}
|
||||
Sequence.SetFailed(
|
||||
InitializationSequence::FK_ParenthesizedListInitFailed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
InitializationKind SubKind = InitializationKind::CreateForInit(
|
||||
E->getExprLoc(), /*isDirectInit=*/false, E);
|
||||
InitializationSequence SubSeq(S, SubEntity, SubKind, E);
|
||||
|
||||
if (SubSeq.Failed()) {
|
||||
if (!VerifyOnly)
|
||||
SubSeq.Diagnose(S, SubEntity, SubKind, E);
|
||||
else
|
||||
Sequence.SetFailed(
|
||||
InitializationSequence::FK_ParenthesizedListInitFailed);
|
||||
|
||||
return false;
|
||||
}
|
||||
if (!VerifyOnly) {
|
||||
ExprResult ER = SubSeq.Perform(S, SubEntity, SubKind, E);
|
||||
InitExprs.push_back(ER.get());
|
||||
}
|
||||
} else {
|
||||
// We've processed all of the args, but there are still entities that
|
||||
// have to be initialized.
|
||||
if (SubEntity.getKind() == InitializedEntity::EK_Member) {
|
||||
// C++ [dcl.init]p17.6.2.2
|
||||
// The remaining elements are initialized with their default member
|
||||
// initializers, if any
|
||||
auto *FD = cast<FieldDecl>(SubEntity.getDecl());
|
||||
if (Expr *ICE = FD->getInClassInitializer(); ICE && !VerifyOnly) {
|
||||
ExprResult DIE = S.BuildCXXDefaultInitExpr(FD->getLocation(), FD);
|
||||
if (DIE.isInvalid())
|
||||
return false;
|
||||
S.checkInitializerLifetime(SubEntity, DIE.get());
|
||||
InitExprs.push_back(DIE.get());
|
||||
continue;
|
||||
};
|
||||
}
|
||||
// Remaining class elements without default member initializers and
|
||||
// array elements are value initialized:
|
||||
//
|
||||
// C++ [dcl.init]p17.6.2.2
|
||||
// The remaining elements...otherwise are value initialzed
|
||||
//
|
||||
// C++ [dcl.init]p17.5
|
||||
// if the destination type is an array, the object is initialized as
|
||||
// . follows. Let x1, . . . , xk be the elements of the expression-list
|
||||
// ...Let n denote the array size...the ith array element is...value-
|
||||
// initialized for each k < i <= n.
|
||||
InitializationKind SubKind = InitializationKind::CreateValue(
|
||||
Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true);
|
||||
InitializationSequence SubSeq(S, SubEntity, SubKind, std::nullopt);
|
||||
if (SubSeq.Failed()) {
|
||||
if (!VerifyOnly)
|
||||
SubSeq.Diagnose(S, SubEntity, SubKind, std::nullopt);
|
||||
return false;
|
||||
}
|
||||
if (!VerifyOnly) {
|
||||
ExprResult ER = SubSeq.Perform(S, SubEntity, SubKind, std::nullopt);
|
||||
if (SubEntity.getKind() == InitializedEntity::EK_ArrayElement) {
|
||||
ArrayFiller = ER.get();
|
||||
return true;
|
||||
}
|
||||
InitExprs.push_back(ER.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (const ArrayType *AT =
|
||||
S.getASTContext().getAsArrayType(Entity.getType())) {
|
||||
|
||||
SmallVector<InitializedEntity, 4> ElementEntities;
|
||||
uint64_t ArrayLength;
|
||||
// C++ [dcl.init]p17.5
|
||||
// if the destination type is an array, the object is initialized as
|
||||
// follows. Let x1, . . . , xk be the elements of the expression-list. If
|
||||
// the destination type is an array of unknown bound, it is define as
|
||||
// having k elements.
|
||||
if (const ConstantArrayType *CAT =
|
||||
S.getASTContext().getAsConstantArrayType(Entity.getType()))
|
||||
ArrayLength = CAT->getSize().getZExtValue();
|
||||
else
|
||||
ArrayLength = Args.size();
|
||||
|
||||
if (ArrayLength >= Args.size()) {
|
||||
for (uint64_t I = 0; I < ArrayLength; ++I)
|
||||
ElementEntities.push_back(
|
||||
InitializedEntity::InitializeElement(S.getASTContext(), I, Entity));
|
||||
|
||||
if (!ProcessEntities(ElementEntities))
|
||||
return;
|
||||
|
||||
ResultType = S.Context.getConstantArrayType(
|
||||
AT->getElementType(), llvm::APInt(32, ArrayLength), nullptr,
|
||||
ArrayType::Normal, 0);
|
||||
}
|
||||
} else if (auto *RT = Entity.getType()->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
|
||||
auto BaseRange = map_range(RD->bases(), [&S](auto &base) {
|
||||
return InitializedEntity::InitializeBase(S.getASTContext(), &base, false);
|
||||
});
|
||||
auto FieldRange = map_range(RD->fields(), [](auto *field) {
|
||||
return InitializedEntity::InitializeMember(field);
|
||||
});
|
||||
|
||||
if (!ProcessEntities(BaseRange))
|
||||
return;
|
||||
|
||||
if (!ProcessEntities(FieldRange))
|
||||
return;
|
||||
|
||||
ResultType = Entity.getType();
|
||||
}
|
||||
|
||||
// Not all of the args have been processed, so there must've been more args
|
||||
// then were required to initialize the element.
|
||||
if (ArgIndexToProcess < Args.size()) {
|
||||
Sequence.SetFailed(InitializationSequence::FK_ParenthesizedListInitFailed);
|
||||
if (!VerifyOnly) {
|
||||
QualType T = Entity.getType();
|
||||
int InitKind = T->isArrayType() ? 0 : T->isUnionType() ? 3 : 4;
|
||||
S.Diag(Kind.getLocation(), diag::err_excess_initializers)
|
||||
<< InitKind << Args[ArgIndexToProcess]->getSourceRange();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (VerifyOnly) {
|
||||
Sequence.setSequenceKind(InitializationSequence::NormalSequence);
|
||||
Sequence.AddParenthesizedListInitStep(Entity.getType());
|
||||
} else if (Result) {
|
||||
SourceRange SR = Kind.getParenOrBraceRange();
|
||||
auto *CPLIE = CXXParenListInitExpr::Create(
|
||||
S.getASTContext(), InitExprs, ResultType, Args.size(),
|
||||
Kind.getLocation(), SR.getBegin(), SR.getEnd());
|
||||
CPLIE->setArrayFiller(ArrayFiller);
|
||||
*Result = CPLIE;
|
||||
S.Diag(Kind.getLocation(),
|
||||
diag::warn_cxx17_compat_aggregate_init_paren_list)
|
||||
<< Kind.getLocation() << SR << ResultType;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// Attempt a user-defined conversion between two types (C++ [dcl.init]),
|
||||
/// which enumerates all conversion functions and performs overload resolution
|
||||
/// to select the best.
|
||||
@ -6116,11 +5915,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
|
||||
TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer),
|
||||
*this, TreatUnavailableAsInvalid);
|
||||
AddParenthesizedArrayInitStep(DestType);
|
||||
} else if (S.getLangOpts().CPlusPlus20 && !TopLevelOfInitList &&
|
||||
Kind.getKind() == InitializationKind::IK_Direct)
|
||||
TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
|
||||
/*VerifyOnly=*/true);
|
||||
else if (DestAT->getElementType()->isCharType())
|
||||
} else if (DestAT->getElementType()->isCharType())
|
||||
SetFailed(FK_ArrayNeedsInitListOrStringLiteral);
|
||||
else if (IsWideCharCompatible(DestAT->getElementType(), Context))
|
||||
SetFailed(FK_ArrayNeedsInitListOrWideStringLiteral);
|
||||
@ -6167,39 +5962,18 @@ void InitializationSequence::InitializeFrom(Sema &S,
|
||||
if (Kind.getKind() == InitializationKind::IK_Direct ||
|
||||
(Kind.getKind() == InitializationKind::IK_Copy &&
|
||||
(Context.hasSameUnqualifiedType(SourceType, DestType) ||
|
||||
S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType, DestType)))) {
|
||||
TryConstructorInitialization(S, Entity, Kind, Args, DestType, DestType,
|
||||
*this);
|
||||
|
||||
// We fall back to the "no matching constructor" path if the
|
||||
// failed candidate set has functions other than the three default
|
||||
// constructors. For example, conversion function.
|
||||
if (const auto *RD =
|
||||
dyn_cast<CXXRecordDecl>(DestType->getAs<RecordType>()->getDecl());
|
||||
// In general, we should call isCompleteType for RD to check its
|
||||
// completeness, we don't call it here as it was already called in the
|
||||
// above TryConstructorInitialization.
|
||||
S.getLangOpts().CPlusPlus20 && RD && RD->hasDefinition() &&
|
||||
RD->isAggregate() && Failed() &&
|
||||
getFailureKind() == FK_ConstructorOverloadFailed) {
|
||||
// C++20 [dcl.init] 17.6.2.2:
|
||||
// - Otherwise, if no constructor is viable, the destination type is
|
||||
// an
|
||||
// aggregate class, and the initializer is a parenthesized
|
||||
// expression-list.
|
||||
TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
|
||||
/*VerifyOnly=*/true);
|
||||
}
|
||||
} else {
|
||||
// - Otherwise (i.e., for the remaining copy-initialization cases),
|
||||
// user-defined conversion sequences that can convert from the
|
||||
// source type to the destination type or (when a conversion
|
||||
// function is used) to a derived class thereof are enumerated as
|
||||
// described in 13.3.1.4, and the best one is chosen through
|
||||
// overload resolution (13.3).
|
||||
S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType, DestType))))
|
||||
TryConstructorInitialization(S, Entity, Kind, Args,
|
||||
DestType, DestType, *this);
|
||||
// - Otherwise (i.e., for the remaining copy-initialization cases),
|
||||
// user-defined conversion sequences that can convert from the source
|
||||
// type to the destination type or (when a conversion function is
|
||||
// used) to a derived class thereof are enumerated as described in
|
||||
// 13.3.1.4, and the best one is chosen through overload resolution
|
||||
// (13.3).
|
||||
else
|
||||
TryUserDefinedConversion(S, DestType, Kind, Initializer, *this,
|
||||
TopLevelOfInitList);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -8459,7 +8233,6 @@ ExprResult InitializationSequence::Perform(Sema &S,
|
||||
case SK_ConstructorInitializationFromList:
|
||||
case SK_StdInitializerListConstructorCall:
|
||||
case SK_ZeroInitialization:
|
||||
case SK_ParenthesizedListInit:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -9149,14 +8922,6 @@ ExprResult InitializationSequence::Perform(Sema &S,
|
||||
CurInit.get()->getValueKind());
|
||||
break;
|
||||
}
|
||||
case SK_ParenthesizedListInit: {
|
||||
CurInit = nullptr;
|
||||
TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
|
||||
/*VerifyOnly=*/false, &CurInit);
|
||||
if (CurInit.get() && ResultType)
|
||||
*ResultType = CurInit.get()->getType();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9758,11 +9523,6 @@ bool InitializationSequence::Diagnose(Sema &S,
|
||||
diag::note_explicit_ctor_deduction_guide_here) << false;
|
||||
break;
|
||||
}
|
||||
|
||||
case FK_ParenthesizedListInitFailed:
|
||||
TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
|
||||
/*VerifyOnly=*/false);
|
||||
break;
|
||||
}
|
||||
|
||||
PrintInitLocationNote(S, Entity);
|
||||
@ -9929,10 +9689,6 @@ void InitializationSequence::dump(raw_ostream &OS) const {
|
||||
case FK_ExplicitConstructor:
|
||||
OS << "list copy initialization chose explicit constructor";
|
||||
break;
|
||||
|
||||
case FK_ParenthesizedListInitFailed:
|
||||
OS << "parenthesized list initialization failed";
|
||||
break;
|
||||
}
|
||||
OS << '\n';
|
||||
return;
|
||||
@ -10104,9 +9860,6 @@ void InitializationSequence::dump(raw_ostream &OS) const {
|
||||
case SK_OCLZeroOpaqueType:
|
||||
OS << "OpenCL opaque type from zero";
|
||||
break;
|
||||
case SK_ParenthesizedListInit:
|
||||
OS << "initialization from a parenthesized list of values";
|
||||
break;
|
||||
}
|
||||
|
||||
OS << " [" << S->Type << ']';
|
||||
|
||||
@ -3859,16 +3859,6 @@ public:
|
||||
return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator);
|
||||
}
|
||||
|
||||
ExprResult RebuildCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
|
||||
unsigned NumUserSpecifiedExprs,
|
||||
SourceLocation InitLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation RParenLoc) {
|
||||
return CXXParenListInitExpr::Create(getSema().Context, Args, T,
|
||||
NumUserSpecifiedExprs, InitLoc,
|
||||
LParenLoc, RParenLoc);
|
||||
}
|
||||
|
||||
/// Build a new atomic operation expression.
|
||||
///
|
||||
/// By default, performs semantic analysis to build the new expression.
|
||||
@ -14037,20 +14027,6 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
ExprResult
|
||||
TreeTransform<Derived>::TransformCXXParenListInitExpr(CXXParenListInitExpr *E) {
|
||||
SmallVector<Expr *, 4> TransformedInits;
|
||||
ArrayRef<Expr *> InitExprs = E->getInitExprs();
|
||||
if (TransformExprs(InitExprs.data(), InitExprs.size(), true,
|
||||
TransformedInits))
|
||||
return ExprError();
|
||||
|
||||
return getDerived().RebuildCXXParenListInitExpr(
|
||||
TransformedInits, E->getType(), E->getUserSpecifiedInitExprs().size(),
|
||||
E->getInitLoc(), E->getBeginLoc(), E->getEndLoc());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
ExprResult
|
||||
TreeTransform<Derived>::TransformCXXStdInitializerListExpr(
|
||||
|
||||
@ -2175,26 +2175,6 @@ void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) {
|
||||
E->Opcode = (BinaryOperatorKind)Record.readInt();
|
||||
}
|
||||
|
||||
void ASTStmtReader::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
|
||||
VisitExpr(E);
|
||||
unsigned ExpectedNumExprs = Record.readInt();
|
||||
assert(E->NumExprs == ExpectedNumExprs &&
|
||||
"expected number of expressions does not equal the actual number of "
|
||||
"serialized expressions.");
|
||||
E->NumUserSpecifiedExprs = Record.readInt();
|
||||
E->InitLoc = readSourceLocation();
|
||||
E->LParenLoc = readSourceLocation();
|
||||
E->RParenLoc = readSourceLocation();
|
||||
for (unsigned I = 0; I < ExpectedNumExprs; I++)
|
||||
E->getTrailingObjects<Expr *>()[I] = Record.readSubExpr();
|
||||
|
||||
bool HasArrayFiller = Record.readBool();
|
||||
if (HasArrayFiller) {
|
||||
E->setArrayFiller(Record.readSubExpr());
|
||||
}
|
||||
E->updateDependence();
|
||||
}
|
||||
|
||||
void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
|
||||
VisitExpr(E);
|
||||
E->SourceExpr = Record.readSubExpr();
|
||||
@ -3986,11 +3966,6 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
|
||||
S = new (Context) CXXFoldExpr(Empty);
|
||||
break;
|
||||
|
||||
case EXPR_CXX_PAREN_LIST_INIT:
|
||||
S = CXXParenListInitExpr::CreateEmpty(
|
||||
Context, /*numExprs=*/Record[ASTStmtReader::NumExprFields], Empty);
|
||||
break;
|
||||
|
||||
case EXPR_OPAQUE_VALUE:
|
||||
S = new (Context) OpaqueValueExpr(Empty);
|
||||
break;
|
||||
|
||||
@ -743,7 +743,6 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
|
||||
RECORD(EXPR_USER_DEFINED_LITERAL);
|
||||
RECORD(EXPR_CXX_STD_INITIALIZER_LIST);
|
||||
RECORD(EXPR_CXX_BOOL_LITERAL);
|
||||
RECORD(EXPR_CXX_PAREN_LIST_INIT);
|
||||
RECORD(EXPR_CXX_NULL_PTR_LITERAL);
|
||||
RECORD(EXPR_CXX_TYPEID_EXPR);
|
||||
RECORD(EXPR_CXX_TYPEID_TYPE);
|
||||
|
||||
@ -2081,23 +2081,6 @@ void ASTStmtWriter::VisitCXXFoldExpr(CXXFoldExpr *E) {
|
||||
Code = serialization::EXPR_CXX_FOLD;
|
||||
}
|
||||
|
||||
void ASTStmtWriter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
|
||||
VisitExpr(E);
|
||||
ArrayRef<Expr *> InitExprs = E->getInitExprs();
|
||||
Record.push_back(InitExprs.size());
|
||||
Record.push_back(E->getUserSpecifiedInitExprs().size());
|
||||
Record.AddSourceLocation(E->getInitLoc());
|
||||
Record.AddSourceLocation(E->getBeginLoc());
|
||||
Record.AddSourceLocation(E->getEndLoc());
|
||||
for (Expr *InitExpr : E->getInitExprs())
|
||||
Record.AddStmt(InitExpr);
|
||||
bool HasArrayFiller = E->getArrayFiller();
|
||||
Record.push_back(HasArrayFiller);
|
||||
if (HasArrayFiller)
|
||||
Record.AddStmt(E->getArrayFiller());
|
||||
Code = serialization::EXPR_CXX_PAREN_LIST_INIT;
|
||||
}
|
||||
|
||||
void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
|
||||
VisitExpr(E);
|
||||
Record.AddStmt(E->getSourceExpr());
|
||||
|
||||
@ -1901,7 +1901,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
||||
case Stmt::ConceptSpecializationExprClass:
|
||||
case Stmt::CXXRewrittenBinaryOperatorClass:
|
||||
case Stmt::RequiresExprClass:
|
||||
case Expr::CXXParenListInitExprClass:
|
||||
// Fall through.
|
||||
|
||||
// Cases we intentionally don't evaluate, since they don't need
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fexceptions -fcxx-exceptions -verify=expected,pre20 %s
|
||||
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fexceptions -fcxx-exceptions -verify=expected,post20 %s
|
||||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
|
||||
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
|
||||
|
||||
template<typename... Types> struct tuple;
|
||||
template<int I> struct int_c;
|
||||
@ -99,12 +99,12 @@ struct HasMixins : public Mixins... {
|
||||
HasMixins(int i);
|
||||
};
|
||||
|
||||
struct A { }; // pre20-note{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const A' for 1st argument}} \
|
||||
// pre20-note{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'A' for 1st argument}} \
|
||||
// pre20-note{{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
|
||||
struct B { }; // pre20-note{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const B' for 1st argument}} \
|
||||
// pre20-note{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'B' for 1st argument}} \
|
||||
// pre20-note{{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
|
||||
struct A { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const A' for 1st argument}} \
|
||||
// expected-note{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'A' for 1st argument}} \
|
||||
// expected-note{{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
|
||||
struct B { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const B' for 1st argument}} \
|
||||
// expected-note{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'B' for 1st argument}} \
|
||||
// expected-note{{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
|
||||
struct C { };
|
||||
struct D { };
|
||||
|
||||
@ -126,10 +126,8 @@ HasMixins<Mixins...>::HasMixins(const HasMixins &other): Mixins(other)... { }
|
||||
|
||||
template<typename ...Mixins>
|
||||
HasMixins<Mixins...>::HasMixins(int i): Mixins(i)... { }
|
||||
// pre20-error@-1 {{no matching constructor for initialization of 'A'}}
|
||||
// pre20-error@-2 {{no matching constructor for initialization of 'B'}}
|
||||
// post20-error@-3 {{excess elements in struct initializer}}
|
||||
// post20-error@-4 {{excess elements in struct initializer}}
|
||||
// expected-error@-1 {{no matching constructor for initialization of 'A'}}
|
||||
// expected-error@-2 {{no matching constructor for initialization of 'B'}}
|
||||
|
||||
void test_has_mixins() {
|
||||
HasMixins<A, B> ab;
|
||||
|
||||
@ -1,351 +0,0 @@
|
||||
// RUN: %clang_cc1 -std=c++20 %s -emit-llvm -triple x86_64-unknown-linux-gnu -o - | FileCheck %s
|
||||
|
||||
template <typename T>
|
||||
struct IsChar {
|
||||
constexpr operator bool() const { return false; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct IsChar<char> {
|
||||
constexpr operator bool() const { return true; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept SameAsChar = (bool)IsInt<T>();
|
||||
|
||||
// CHECK-DAG: [[STRUCT_A:%.*]] = type { i8, double }
|
||||
struct A {
|
||||
char i;
|
||||
double j;
|
||||
|
||||
template <SameAsChar T>
|
||||
operator T() const { return i; };
|
||||
};
|
||||
|
||||
// CHECK-DAG: [[STRUCT_B:%.*]] = type { [[STRUCT_A]], i32 }
|
||||
struct B {
|
||||
A a;
|
||||
int b;
|
||||
};
|
||||
|
||||
// CHECK-DAG: [[STRUCT_C:%.*]] = type <{ [[STRUCT_B]], [[STRUCT_A]], i32, [4 x i8] }>
|
||||
struct C : public B, public A {
|
||||
int c;
|
||||
};
|
||||
|
||||
// CHECK-DAG: [[STRUCT_D:%.*]] = type { [[STRUCT_A]], [[STRUCT_A]], i8, [[STRUCT_A]] }
|
||||
struct D {
|
||||
A a;
|
||||
A b = A{2, 2.0};
|
||||
unsigned : 2;
|
||||
A c;
|
||||
};
|
||||
|
||||
// CHECK-DAG: [[STRUCT_E:%.*]] = type { i32, ptr }
|
||||
struct E {
|
||||
int a;
|
||||
const char* fn = __builtin_FUNCTION();
|
||||
~E() {};
|
||||
};
|
||||
|
||||
// CHECK-DAG: [[STRUCT_F:%.*]] = type { i8 }
|
||||
struct F {
|
||||
F (int i = 1);
|
||||
F (const F &f) = delete;
|
||||
F (F &&f) = default;
|
||||
};
|
||||
|
||||
// CHECK-DAG: [[STRUCT_G:%.*]] = type <{ i32, [[STRUCT_F]], [3 x i8] }>
|
||||
struct G {
|
||||
int a;
|
||||
F f;
|
||||
};
|
||||
|
||||
// CHECK-DAG: [[UNION_U:%.*]] = type { [[STRUCT_A]] }
|
||||
// CHECK-DAG: [[STR:@.*]] = private unnamed_addr constant [6 x i8] {{.*}}foo18{{.*}}, align 1
|
||||
union U {
|
||||
unsigned : 1;
|
||||
A a;
|
||||
char b;
|
||||
};
|
||||
|
||||
// CHECK-DAG: [[A1:@.*a1.*]] = internal constant [[STRUCT_A]] { i8 3, double 2.000000e+00 }, align 8
|
||||
constexpr A a1(3.1, 2.0);
|
||||
// CHECK-DAG: [[A2:@.*a2.*]] = internal constant [[STRUCT_A]] { i8 99, double 0.000000e+00 }, align 8
|
||||
constexpr auto a2 = static_cast<A>('c');
|
||||
// CHECK-DAG: [[B1:@.*b1.*]] = internal constant [[STRUCT_B]] { [[STRUCT_A]] { i8 99, double 0.000000e+00 }, i32 0 }, align 8
|
||||
constexpr B b1(A('c'));
|
||||
// CHECK-DAG: [[C1:@.*c1.*]] = internal constant { [[STRUCT_A]], i32, [4 x i8], i8, double, i32 } { [[STRUCT_A]] { i8 99, double 0.000000e+00 }, i32 0, [4 x i8] undef, i8 3, double 2.000000e+00, i32 0 }, align
|
||||
constexpr C c1(b1, a1);
|
||||
// CHECK-DAG: [[U1:@.*u1.*]] = internal constant [[UNION_U]] { [[STRUCT_A]] { i8 1, double 1.000000e+00 } }, align 8
|
||||
constexpr U u1(A(1, 1));
|
||||
// CHECK-DAG: [[D1:@.*d1.*]] = internal constant { [[STRUCT_A]], [[STRUCT_A]], [8 x i8], [[STRUCT_A]] } { [[STRUCT_A]] { i8 2, double 2.000000e+00 }, [[STRUCT_A]] { i8 2, double 2.000000e+00 }, [8 x i8] undef, [[STRUCT_A]] zeroinitializer }, align 8
|
||||
constexpr D d1(A(2, 2));
|
||||
// CHECK-DAG: [[ARR1:@.*arr1.*]] = internal constant [3 x i32] [i32 1, i32 2, i32 0], align 4
|
||||
constexpr int arr1[3](1, 2);
|
||||
// CHECK-DAG: [[ARR4:@.*arr4.*]] = internal constant [1 x i32] [i32 1], align 4
|
||||
constexpr int arr4[](1);
|
||||
// CHECK-DAG: [[ARR5:@.*arr5.*]] = internal constant [2 x i32] [i32 2, i32 0], align 4
|
||||
constexpr int arr5[2](2);
|
||||
|
||||
// CHECK: define dso_local { i8, double } @{{.*foo1.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_A]], align 8
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[A1]], i64 16, i1 false)
|
||||
// CHECK-NEXT: [[TMP_0:%.*]] = load { i8, double }, ptr [[RETVAL]], align 8
|
||||
// CHECK-NEXT: ret { i8, double } [[TMP_0]]
|
||||
A foo1() {
|
||||
return a1;
|
||||
}
|
||||
|
||||
// CHECK: define dso_local void @{{.*foo2.*}}(ptr noalias sret([[STRUCT_B]]) align 8 [[AGG_RESULT:%.*]])
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[AGG_RESULT]], ptr align 8 [[B1]], i64 24, i1 false)
|
||||
// CHECK-NEXT: ret void
|
||||
B foo2() {
|
||||
return b1;
|
||||
}
|
||||
|
||||
// CHECK: define dso_local void @{{.*foo3.*}}(ptr noalias sret([[STRUCT_C]]) align 8 [[AGG_RESULT:%.*]])
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[AGG_RESULT]], ptr align 8 [[C1]], i64 48, i1 false)
|
||||
// CHECK-NEXT: ret void
|
||||
C foo3() {
|
||||
return c1;
|
||||
}
|
||||
|
||||
// CHECK: define dso_local void @{{.*foo4.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[C2:%.*]] = alloca [[STRUCT_C:%.*]], align 8
|
||||
// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_B:%.*]], align 8
|
||||
// CHECK-NEXT: [[REF_TMP_1:%.*]] = alloca [[STRUCT_A:%.*]], align 8
|
||||
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_B]], ptr [[REF_TMP]], i32 0, i32 0
|
||||
// CHECK-NEXT: [[I:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[A]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i8 1, ptr [[I]], align 8
|
||||
// CHECK-NEXT: [[J:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[A]], i32 0, i32 1
|
||||
// CHECK-NEXT: store double 1.000000e+00, ptr [[J]], align 8
|
||||
// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_B]], ptr [[REF_TMP]], i32 0, i32 1
|
||||
// CHECK-NEXT: store i32 1, ptr [[B]], align 8
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[C2]], ptr align 8 [[REF_TMP]], i64 24, i1 false)
|
||||
// CHECK-NEXT: [[TMP_0:%.*]] = getelementptr inbounds i8, ptr [[C2]], i64 24
|
||||
// CHECK-NEXT: [[I2:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[REF_TMP_1]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i8 97, ptr [[I2]], align 8
|
||||
// CHECK-NEXT: [[J3:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[REF_TMP_1]], i32 0, i32 1
|
||||
// CHECK-NEXT: store double 0.000000e+00, ptr [[J3]], align 8
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP_0]], ptr align 8 [[REF_TMP_1]], i64 16, i1 false)
|
||||
// CHECK-NEXT: [[C:%.*]] = getelementptr inbounds %struct.C, ptr %c2, i32 0, i32 2
|
||||
// CHECK-NEXT: store i32 2, ptr %c, align 8
|
||||
// CHECK-NEXT: ret void
|
||||
void foo4() {
|
||||
C c2(B(A(1, 1), 1), A('a'), 2);
|
||||
}
|
||||
|
||||
// CHECK: define dso_local { i64, double } @{{.*foo5.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT [[RETVAL:%.*]] = alloca [[UNION_U]], align 8
|
||||
// CHECK-NEXT call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[U1]], i64 16, i1 false)
|
||||
// CHECK-NEXT [[COERCE_DIVE:%.*]] = getelementptr inbounds [[UNION_U]], ptr %retval, i32 0, i32 0
|
||||
// CHECK-NEXT [[TMP_0:%.*]] = load { i64, double }, ptr [[COERCE_DIVE]], align 8
|
||||
// CHECK-NEXT ret { i64, double } [[TMP_0]]
|
||||
U foo5() {
|
||||
return u1;
|
||||
}
|
||||
|
||||
|
||||
// CHECK: define dso_local { i64, double } @{{.*foo6.*}}(i8 [[A_COERCE_0:%.*]], double [[A_COERCE_1:%.*]])
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[UNION_U]], align 8
|
||||
// CHECK-NEXT: [[A:%.*]] = alloca [[STRUCT_A]], align 8
|
||||
// CHECK-NEXT: [[TMP_0:%.*]] = getelementptr inbounds { i8, double }, ptr [[A]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i8 [[A_COERCE_0]], ptr [[TMP_0]], align 8
|
||||
// CHECK-NEXT: [[TMP_1:%.*]] = getelementptr inbounds { i8, double }, ptr [[A]], i32 0, i32 1
|
||||
// CHECK-NEXT: store double [[A_COERCE_1]], ptr [[TMP_1]], align 8
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[A]], i64 16, i1 false)
|
||||
// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds [[UNION_U]], ptr [[RETVAL]], i32 0, i32 0
|
||||
// CHECK-NEXT: [[TMP_2:%.*]] = load { i64, double }, ptr [[COERCE_DIVE:%.*]], align 8
|
||||
// CHECK-NEXT: ret { i64, double } [[TMP_2]]
|
||||
U foo6(A a) {
|
||||
return U(a);
|
||||
}
|
||||
|
||||
// CHECK: define dso_local void @{{.*foo7.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[D:%.*]] = alloca [[STRUCT_D:%.*]], align 8
|
||||
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 0
|
||||
// CHECK-NEXT: [[I]] = getelementptr inbounds [[STRUCT_A:%.*]], ptr [[A]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i8 1, ptr [[I]], align 8
|
||||
// CHECK-NEXT: [[J:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[A]], i32 0, i32 1
|
||||
// CHECK-NEXT: store double 1.000000e+00, ptr [[J]], align 8
|
||||
// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 1
|
||||
// CHECK-NEXT: [[I1:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[B]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i8 11, ptr [[I1]], align 8
|
||||
// CHECK-NEXT: [[J2:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[B]], i32 0, i32 1
|
||||
// CHECK-NEXT: store double 1.100000e+01, ptr [[J2]], align 8
|
||||
// CHECK-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 3
|
||||
// CHECK-NEXT: [[I3:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[C]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i8 111, ptr [[I3]], align 8
|
||||
// CHECK-NEXT: [[J4:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[C]], i32 0, i32 1
|
||||
// CHECK-NEXT: store double 1.110000e+02, ptr [[J4]], align 8
|
||||
// CHECK-NEXT: ret void
|
||||
void foo7() {
|
||||
D d(A(1, 1), A(11, 11), A(111, 111));
|
||||
}
|
||||
|
||||
// CHECK: dso_local void @{{.*foo8.*}}(ptr noalias sret([[STRUCT_D]]) align 8 [[AGG_RESULT:%.*]])
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[AGG_RESULT]], ptr align 8 [[D1]], i64 56, i1 false)
|
||||
// CHECK-NEXT: ret void
|
||||
D foo8() {
|
||||
return d1;
|
||||
}
|
||||
|
||||
// CHECK: define dso_local void @{{.*foo9.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[D:%.*]] = alloca [[STRUCT_D:%.*]], align 8
|
||||
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 0
|
||||
// CHECK-NEXT: [[I]] = getelementptr inbounds [[STRUCT_A:%.*]], ptr [[A]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i8 1, ptr [[I]], align 8
|
||||
// CHECK-NEXT: [[J:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[A]], i32 0, i32 1
|
||||
// CHECK-NEXT: store double 1.000000e+00, ptr [[J]], align 8
|
||||
// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 1
|
||||
// CHECK-NEXT: [[I1:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[B]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i8 2, ptr [[I1]], align 8
|
||||
// CHECK-NEXT: [[J2:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[B]], i32 0, i32 1
|
||||
// CHECK-NEXT: store double 2.000000e+00, ptr [[J2]], align 8
|
||||
// CHECK-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_D]], ptr [[D]], i32 0, i32 3
|
||||
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[C]], i8 0, i64 16, i1 false)
|
||||
// CHECK-NEXT: ret void
|
||||
void foo9() {
|
||||
D d(A(1, 1));
|
||||
}
|
||||
|
||||
// CHECK: define dso_local noundef ptr @{{.*foo10.*}}()
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret ptr [[ARR1]]
|
||||
const int* foo10() {
|
||||
return arr1;
|
||||
}
|
||||
|
||||
// CHECK: define dso_local void @{{.*foo11.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[ARR_2:%.*]] = alloca [4 x i32], align 16
|
||||
// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
|
||||
// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_BEGIN:%.*]] = getelementptr inbounds [4 x i32], ptr [[ARR_2]], i64 0, i64 0
|
||||
// CHECK-NEXT: [[TMP_0:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
||||
// CHECK-NEXT: store i32 [[TMP_0]], ptr [[ARRINIT_BEGIN]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_ELEM:%.*]] = getelementptr inbounds i32, ptr [[ARRINIT_BEGIN]], i64 1
|
||||
// CHECK-NEXT: [[TMP_1:%.*]] = load i32, ptr [[B_ADDR]], align 4
|
||||
// CHECK-NEXT: store i32 [[TMP_1]], ptr [[ARRINIT_ELEM]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_START:%.*]] = getelementptr inbounds i32, ptr [[ARRINIT_ELEM]], i64 1
|
||||
// CHECK-NEXT: [[ARRINIT_END:%.*]] = getelementptr inbounds i32, ptr [[ARRINIT_BEGIN]], i64 4
|
||||
// CHECK-NEXT: br label [[ARRINIT_BODY:%.*]]
|
||||
// CHECK: [[ARRINIT_CUR:%.*]] = phi ptr [ [[ARRINIT_START]], %entry ], [ [[ARRINIT_NEXT:%.*]], [[ARRINIT_BODY]] ]
|
||||
// CHECK-NEXT: store i32 0, ptr [[ARRINIT_CUR]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_NEXT]] = getelementptr inbounds i32, ptr [[ARRINIT_CUR]], i64 1
|
||||
// CHECK-NEXT: [[ARRINIT_DONE:%.*]] = icmp eq ptr [[ARRINIT_NEXT]], [[ARRINIT_END:%.*]]
|
||||
// CHECK-NEXT: br i1 [[ARRINIT_DONE]], label [[ARRINIT_END1:%.*]], label [[ARRINIT_BODY]]
|
||||
// CHECK: ret void
|
||||
void foo11(int a, int b) {
|
||||
int arr2[4](a, b);
|
||||
}
|
||||
|
||||
// CHECK: define dso_local void @{{.*foo12.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[ARR_3:%.*]] = alloca [2 x i32], align 4
|
||||
// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4
|
||||
// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_BEGIN:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARR_3]], i64 0, i64 0
|
||||
// CHECK-NEXT: [[TMP_0:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
||||
// CHECK-NEXT: store i32 [[TMP_0]], ptr [[ARRINIT_BEGIN]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_ELEMENT:%.*]] = getelementptr inbounds i32, ptr [[ARRINIT_BEGIN]], i64 1
|
||||
// CHECK-NEXT: [[TMP_1:%.*]] = load i32, ptr [[B_ADDR]], align 4
|
||||
// CHECK-NEXT: store i32 [[TMP_1]], ptr [[ARRINIT_ELEMENT]], align 4
|
||||
// CHECK-NEXT: ret void
|
||||
void foo12(int a, int b) {
|
||||
int arr3[](a, b);
|
||||
}
|
||||
|
||||
// CHECK: define dso_local { i8, double } @{{.*foo13.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_A]], align 8
|
||||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[A2]], i64 16, i1 false)
|
||||
// CHECK-NEXT: [[TMP_0:%.*]] = load { i8, double }, ptr [[RETVAL]], align 8
|
||||
// CHECK-NEXT: ret { i8, double } [[TMP_0]]
|
||||
A foo13() {
|
||||
return a2;
|
||||
}
|
||||
|
||||
// CHECK: define dso_local noundef ptr @{{.*foo14.*}}()
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret ptr [[ARR4]]
|
||||
const int* foo14() {
|
||||
return arr4;
|
||||
}
|
||||
|
||||
// CHECK: define dso_local noundef ptr @{{.*foo15.*}}()
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret ptr [[ARR5]]
|
||||
const int* foo15() {
|
||||
return arr5;
|
||||
}
|
||||
|
||||
// CHECK: define dso_local void @{{.*foo16.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[ARR_6:%.*arr6.*]] = alloca ptr, align 8
|
||||
// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [1 x i32], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_BEGIN:%.*]] = getelementptr inbounds [1 x i32], ptr [[REF_TMP]], i64 0, i64 0
|
||||
// CHECK-NEXT: store i32 3, ptr [[ARRINIT_BEGIN]], align 4
|
||||
// CHECK-NEXT: store ptr [[REF_TMP]], ptr [[ARR_6]], align 8
|
||||
// CHECK-NEXT: ret void
|
||||
void foo16() {
|
||||
int (&&arr6)[] = static_cast<int[]>(3);
|
||||
}
|
||||
|
||||
// CHECK: define dso_local void @{{.*foo17.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[ARR_7:%.*arr7.*]] = alloca ptr, align 8
|
||||
// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [2 x i32], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_BEGIN:%.*]] = getelementptr inbounds [2 x i32], ptr [[REF_TMP]], i64 0, i64 0
|
||||
// CHECK-NEXT: store i32 4, ptr [[ARRINIT_BEGIN]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_START:%.*]] = getelementptr inbounds i32, ptr [[ARRINIT_BEGIN]], i64 1
|
||||
// CHECK-NEXT: [[ARRINIT_END:%.*]] = getelementptr inbounds i32, ptr [[ARRINIT_BEGIN]], i64 2
|
||||
// CHECK-NEXT: br label [[ARRINIT_BODY]]
|
||||
// CHECK: [[ARRINIT_CUR:%.*]] = phi ptr [ [[ARRINIT_START]], %entry ], [ [[ARRINIT_NEXT:%.*]], [[ARRINIT_BODY]] ]
|
||||
// CHECK-NEXT: store i32 0, ptr [[ARRINIT_CUR]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_NEXT]] = getelementptr inbounds i32, ptr [[ARRINIT_CUR]], i64 1
|
||||
// CHECK-NEXT: [[ARRINIT_DONE:%.*]] = icmp eq ptr [[ARRINIT_NEXT]], [[ARRINIT_END:%.*]]
|
||||
// CHECK-NEXT: br i1 [[ARRINIT_DONE]], label [[ARRINIT_END1:%.*]], label [[ARRINIT_BODY]]
|
||||
// CHECK: store ptr [[REF_TMP]], ptr [[ARR_7]], align 8
|
||||
// CHECK: ret void
|
||||
void foo17() {
|
||||
int (&&arr7)[2] = static_cast<int[2]>(4);
|
||||
}
|
||||
|
||||
// CHECK: define dso_local void @{{.*foo18.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[E:%.*e.*]] = alloca [[STRUCT_E]], align 8
|
||||
// CHECK-NEXT: [[A:%.*a.*]] = getelementptr inbounds [[STRUCT_E]], ptr [[E]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i32 1, ptr [[A]], align 8
|
||||
// CHECK-NEXT: [[FN:%.*fn.*]] = getelementptr inbounds [[STRUCT_E]], ptr [[E]], i32 0, i32 1
|
||||
// CHECK-NEXT: store ptr [[STR]], ptr [[FN]], align 8
|
||||
// CHECK: ret void
|
||||
void foo18() {
|
||||
E e(1);
|
||||
}
|
||||
|
||||
// CHECK: define dso_local void @{{.*foo19.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[G:%.*g.*]] = alloca [[STRUCT_G]], align 4
|
||||
// CHECK-NEXT: [[A:%.*a.*]] = getelementptr inbounds [[STRUCT_G]], ptr [[G]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i32 2, ptr [[A]], align 4
|
||||
// CHECK-NEXT: [[F:%.*f.*]] = getelementptr inbounds [[STRUCT_G]], ptr [[G]], i32 0, i32 1
|
||||
// CHECk-NEXT: call void @{{.*F.*}}(ptr noundef nonnull align 1 dereferenceable(1)) [[F]], ie32 noundef 1)
|
||||
// CHECK: ret void
|
||||
void foo19() {
|
||||
G g(2);
|
||||
}
|
||||
@ -61,7 +61,8 @@
|
||||
|
||||
// --- C++20 features ---
|
||||
|
||||
#if check(aggregate_paren_init, 0, 0, 0, 0, 201902, 201902)
|
||||
#if check(aggregate_paren_init, 0, 0, 0, 0, 0, 0)
|
||||
// FIXME: 201902 in C++20
|
||||
#error "wrong value for __cpp_aggregate_paren_init"
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
// RUN: %clang_cc1 -x c++ -std=c++20 -triple x86_64-unknown-linux-gnu -emit-pch -o %t %S/cxx_paren_init.h
|
||||
// RUN: %clang_cc1 -x c++ -std=c++20 -triple x86_64-unknown-linux-gnu -include-pch %t %s -S -emit-llvm -o - | FileCheck %s
|
||||
|
||||
// CHECK-DAG: [[STRUCT_S:%.*]] = type { i32, i32 }
|
||||
// CHECK-DAG: @{{.*s.*}} = {{(dso_local )?}}global [[STRUCT_S]] { i32 1, i32 2 }, align 4
|
||||
S s = foo(1, 2);
|
||||
|
||||
// CHECK: define dso_local void @{{.*bar.*}}
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[J_ADDR:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[ARR:%.*]] = alloca [4 x i32], align 16
|
||||
// CHECK-NEXT: store i32 [[A:%.*]], ptr [[I_ADDR]], align 4
|
||||
// CHECK-NEXT: store i32 [[B:%.*]], ptr [[J_ADDR]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_BEGIN:%.*]] = getelementptr inbounds [4 x i32], ptr [[ARR]], i64 0, i64 0
|
||||
// CHECK-NEXT: [[TMP_0:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
||||
// CHECK-NEXT: store i32 [[TMP_0]], ptr [[ARRINIT_BEGIN]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_ELEM:%.*]] = getelementptr inbounds i32, ptr [[ARRINIT_BEGIN]], i64 1
|
||||
// CHECK-NEXT: [[TMP_1:%.*]] = load i32, ptr [[J_ADDR]], align 4
|
||||
// CHECK-NEXT: store i32 [[TMP_1]], ptr [[ARRINIT_ELEM]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_START:%.*]] = getelementptr inbounds i32, ptr [[ARRINIT_ELEM]], i64 1
|
||||
// CHECK-NEXT: [[ARRINIT_END:%.*]] = getelementptr inbounds i32, ptr [[ARRINIT_BEGIN]], i64 4
|
||||
// CHECK-NEXT: br label [[ARRINIT_BODY:%.*]]
|
||||
// CHECK: [[ARRINIT_CUR:%.*]] = phi ptr [ [[ARRINIT_START]], %entry ], [ [[ARRINIT_NEXT:%.*]], [[ARRINIT_BODY]] ]
|
||||
// CHECK-NEXT: store i32 0, ptr [[ARRINIT_CUR]], align 4
|
||||
// CHECK-NEXT: [[ARRINIT_NEXT]] = getelementptr inbounds i32, ptr [[ARRINIT_CUR]], i64 1
|
||||
// CHECK-NEXT: [[ARRINIT_DONE:%.*]] = icmp eq ptr [[ARRINIT_NEXT]], [[ARRINIT_END:%.*]]
|
||||
// CHECK-NEXT: br i1 [[ARRINIT_DONE]], label [[ARRINIT_END1:%.*]], label [[ARRINIT_BODY]]
|
||||
// CHECK: ret void
|
||||
@ -1,5 +0,0 @@
|
||||
struct S { int i, j; };
|
||||
|
||||
constexpr S foo(int i, int j) { return S(i, j); };
|
||||
|
||||
void bar(int i, int j) { int arr[4](i, j); };
|
||||
@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -std=c++17 -fsyntax-only %s -verify=expected,pre20 -Wno-c++2a-extensions
|
||||
// RUN: %clang_cc1 -std=c++2a -fsyntax-only %s -verify=expected,post20
|
||||
// RUN: %clang_cc1 -std=c++17 -fsyntax-only %s -verify -Wno-c++2a-extensions
|
||||
// RUN: %clang_cc1 -std=c++2a -fsyntax-only %s -verify
|
||||
|
||||
template <bool b, auto val> struct enable_ifv {};
|
||||
|
||||
@ -20,7 +20,7 @@ namespace special_cases
|
||||
|
||||
template<int a>
|
||||
struct A {
|
||||
// pre20-note@-1+ {{candidate constructor}}
|
||||
// expected-note@-1+ {{candidate constructor}}
|
||||
explicit(1 << a)
|
||||
// expected-note@-1 {{negative shift count -1}}
|
||||
// expected-error@-2 {{explicit specifier argument is not a constant expression}}
|
||||
@ -28,9 +28,8 @@ struct A {
|
||||
};
|
||||
|
||||
A<-1> a(0);
|
||||
// pre20-error@-1 {{no matching constructor}}
|
||||
// post20-error@-2 {{excess elements in struct initializer}}
|
||||
// expected-note@-3 {{in instantiation of template class}}
|
||||
// expected-error@-1 {{no matching constructor}}
|
||||
// expected-note@-2 {{in instantiation of template class}}
|
||||
|
||||
template<int a>
|
||||
struct B {
|
||||
|
||||
@ -1,172 +0,0 @@
|
||||
// RUN: %clang_cc1 -verify -std=c++20 %s -fsyntax-only
|
||||
// RUN: %clang_cc1 -verify=expected,beforecxx20 -Wc++20-extensions -std=c++20 %s -fsyntax-only
|
||||
|
||||
struct A { // expected-note 4{{candidate constructor}}
|
||||
char i;
|
||||
double j;
|
||||
};
|
||||
|
||||
struct B {
|
||||
A a;
|
||||
int b[20];
|
||||
int &&c; // expected-note {{reference member declared here}}
|
||||
};
|
||||
|
||||
struct C { // expected-note 5{{candidate constructor}}
|
||||
A a;
|
||||
int b[20];
|
||||
};
|
||||
|
||||
struct D : public C, public A {
|
||||
int a;
|
||||
};
|
||||
|
||||
struct E { // expected-note 3{{candidate constructor}}
|
||||
struct F {
|
||||
F(int, int);
|
||||
};
|
||||
int a;
|
||||
F f;
|
||||
};
|
||||
|
||||
int getint(); // expected-note {{declared here}}
|
||||
|
||||
struct F {
|
||||
int a;
|
||||
int b = getint(); // expected-note {{non-constexpr function 'getint' cannot be used in a constant expression}}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct G {
|
||||
T t1;
|
||||
T t2;
|
||||
};
|
||||
|
||||
struct H {
|
||||
virtual void foo() = 0;
|
||||
};
|
||||
|
||||
struct I : public H { // expected-note 3{{candidate constructor}}
|
||||
int i, j;
|
||||
void foo() override {}
|
||||
};
|
||||
|
||||
struct J {
|
||||
int a;
|
||||
int b[]; // expected-note {{initialized flexible array member 'b' is here}}
|
||||
};
|
||||
|
||||
union U {
|
||||
int a;
|
||||
char* b;
|
||||
};
|
||||
|
||||
template <typename T, char CH>
|
||||
void bar() {
|
||||
T t = 0;
|
||||
A a(CH, 1.1); // OK; C++ paren list constructors are supported in semantic tree transformations.
|
||||
// beforecxx20-warning@-1 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
T Construct(Args... args) {
|
||||
return T(args...); // OK; variadic arguments can be used in paren list initializers.
|
||||
// beforecxx20-warning@-1 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
|
||||
}
|
||||
|
||||
void foo() {
|
||||
A a1(1954, 9, 21);
|
||||
// expected-error@-1 {{excess elements in struct initializer}}
|
||||
A a2(2.1);
|
||||
// expected-warning@-1 {{implicit conversion from 'double' to 'char'}}
|
||||
// beforecxx20-warning@-2 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
|
||||
A a3(-1.2, 9.8);
|
||||
// expected-warning@-1 {{implicit conversion from 'double' to 'char'}}
|
||||
// beforecxx20-warning@-2 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
|
||||
A a4 = static_cast<A>(1.1);
|
||||
// expected-warning@-1 {{implicit conversion from 'double' to 'char'}}
|
||||
// beforecxx20-warning@-2 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
|
||||
A a5 = (A)3.1;
|
||||
// expected-warning@-1 {{implicit conversion from 'double' to 'char'}}
|
||||
// beforecxx20-warning@-2 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
|
||||
A a6 = A(8.7);
|
||||
// expected-warning@-1 {{implicit conversion from 'double' to 'char'}}
|
||||
// beforecxx20-warning@-2 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
|
||||
|
||||
B b1(2022, {7, 8});
|
||||
// expected-error@-1 {{no viable conversion from 'int' to 'A'}}
|
||||
B b2(A(1), {}, 1);
|
||||
// expected-error@-1 {{reference member 'c' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
|
||||
// beforecxx20-warning@-2 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
|
||||
// beforecxx20-warning@-3 {{aggregate initialization of type 'B' from a parenthesized list of values is a C++20 extension}}
|
||||
|
||||
C c(A(1), 1, 2, 3, 4);
|
||||
// expected-error@-1 {{array initializer must be an initializer list}}
|
||||
// beforecxx20-warning@-2 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
|
||||
D d1(1);
|
||||
// expected-error@-1 {{no viable conversion from 'int' to 'C'}}
|
||||
D d2(C(1));
|
||||
// expected-error@-1 {{no matching conversion for functional-style cast from 'int' to 'C'}}
|
||||
// beforecxx20-warning@-2 {{aggregate initialization of type 'D' from a parenthesized list of values is a C++20 extension}}
|
||||
D d3(C(A(1)), 1);
|
||||
// expected-error@-1 {{no viable conversion from 'int' to 'A'}}
|
||||
// beforecxx20-warning@-2 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
|
||||
// beforecxx20-warning@-3 {{aggregate initialization of type 'C' from a parenthesized list of values is a C++20 extension}}
|
||||
|
||||
int arr1[](0, 1, 2, A(1));
|
||||
// expected-error@-1 {{no viable conversion from 'A' to 'int'}}
|
||||
// beforecxx20-warning@-2 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
|
||||
|
||||
int arr2[2](0, 1, 2);
|
||||
// expected-error@-1 {{excess elements in array initializer}}
|
||||
|
||||
// We should not build paren list initilizations for IK_COPY.
|
||||
int arr3[1] = 1;
|
||||
// expected-error@-1 {{array initializer must be an initializer list}}
|
||||
|
||||
U u1("abcd");
|
||||
// expected-error@-1 {{cannot initialize a member subobject of type 'int' with an lvalue of type 'const char[5]'}}
|
||||
U u2(1, "efgh");
|
||||
// expected-error@-1 {{excess elements in union initializer}}
|
||||
|
||||
E e1(1);
|
||||
// expected-error@-1 {{no matching constructor for initialization of 'E'}}
|
||||
|
||||
constexpr F f1(1);
|
||||
// expected-error@-1 {{constexpr variable 'f1' must be initialized by a constant expression}}
|
||||
// beforecxx20-warning@-2 {{aggregate initialization of type 'const F' from a parenthesized list of values is a C++20 extension}}
|
||||
|
||||
constexpr F f2(1, 1); // OK: f2.b is initialized by a constant expression.
|
||||
// beforecxx20-warning@-1 {{aggregate initialization of type 'const F' from a parenthesized list of values is a C++20 extension}}
|
||||
|
||||
bar<char, 1>();
|
||||
|
||||
G<char> g('b', 'b');
|
||||
// beforecxx20-warning@-1 {{aggregate initialization of type 'G<char>' from a parenthesized list of values is a C++20 extension}}
|
||||
|
||||
A a7 = Construct<A>('i', 2.2);
|
||||
// beforecxx20-note@-1 {{in instantiation of function template specialization 'Construct<A, char, double>' requested here}}
|
||||
|
||||
int arr4[](1, 2);
|
||||
// beforecxx20-warning@-1 {{aggregate initialization of type 'int[2]' from a parenthesized list of values is a C++20 extension}}
|
||||
|
||||
int arr5[2](1, 2);
|
||||
// beforecxx20-warning@-1 {{aggregate initialization of type 'int[2]' from a parenthesized list of values is a C++20 extension}}
|
||||
|
||||
I i(1, 2);
|
||||
// expected-error@-1 {{no matching constructor for initialization of 'I'}}
|
||||
|
||||
J j(1, {2, 3});
|
||||
// expected-error@-1 {{initialization of flexible array member is not allowed}}
|
||||
|
||||
static_assert(__is_trivially_constructible(A, char, double));
|
||||
static_assert(__is_trivially_constructible(A, char, int));
|
||||
static_assert(__is_trivially_constructible(A, char));
|
||||
|
||||
static_assert(__is_trivially_constructible(D, C, A, int));
|
||||
static_assert(__is_trivially_constructible(D, C));
|
||||
|
||||
static_assert(__is_trivially_constructible(int[2], int, int));
|
||||
static_assert(__is_trivially_constructible(int[2], int, double));
|
||||
static_assert(__is_trivially_constructible(int[2], int));
|
||||
}
|
||||
@ -1,6 +1,4 @@
|
||||
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -o - %s -std=gnu++17 -fsyntax-only -verify
|
||||
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -o - %s -std=gnu++20 -fsyntax-only -verify
|
||||
|
||||
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -frecovery-ast -frecovery-ast-type -o - %s -std=gnu++17 -fsyntax-only -verify
|
||||
|
||||
namespace test0 {
|
||||
struct Indestructible {
|
||||
@ -173,13 +171,3 @@ void f() {
|
||||
S.m(1); // no crash
|
||||
}
|
||||
}
|
||||
|
||||
namespace test16 {
|
||||
// verify we do not crash on incomplete class type.
|
||||
template<typename T, typename U> struct A; // expected-note 5{{template is declared here}}
|
||||
A<int, int> foo() { // expected-error {{implicit instantiation of undefined template}}
|
||||
if (1 == 1)
|
||||
return A<int, int>{1}; // expected-error 2{{implicit instantiation of undefined template}}
|
||||
return A<int, int>(1); // expected-error 2{{implicit instantiation of undefined template}}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2139,7 +2139,6 @@ public:
|
||||
void VisitLambdaExpr(const LambdaExpr *E);
|
||||
void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
|
||||
void VisitRequiresExpr(const RequiresExpr *E);
|
||||
void VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
|
||||
void VisitOMPExecutableDirective(const OMPExecutableDirective *D);
|
||||
void VisitOMPLoopBasedDirective(const OMPLoopBasedDirective *D);
|
||||
void VisitOMPLoopDirective(const OMPLoopDirective *D);
|
||||
@ -3007,9 +3006,6 @@ void EnqueueVisitor::VisitRequiresExpr(const RequiresExpr *E) {
|
||||
for (ParmVarDecl *VD : E->getLocalParameters())
|
||||
AddDecl(VD);
|
||||
}
|
||||
void EnqueueVisitor::VisitCXXParenListInitExpr(const CXXParenListInitExpr *E) {
|
||||
EnqueueChildren(E);
|
||||
}
|
||||
void EnqueueVisitor::VisitPseudoObjectExpr(const PseudoObjectExpr *E) {
|
||||
// Treat the expression like its syntactic form.
|
||||
Visit(E->getSyntacticForm());
|
||||
@ -5591,8 +5587,6 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
|
||||
return cxstring::createRef("ConceptSpecializationExpr");
|
||||
case CXCursor_RequiresExpr:
|
||||
return cxstring::createRef("RequiresExpr");
|
||||
case CXCursor_CXXParenListInitExpr:
|
||||
return cxstring::createRef("CXXParenListInitExpr");
|
||||
case CXCursor_UnexposedStmt:
|
||||
return cxstring::createRef("UnexposedStmt");
|
||||
case CXCursor_DeclStmt:
|
||||
|
||||
@ -643,10 +643,6 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
|
||||
K = CXCursor_RequiresExpr;
|
||||
break;
|
||||
|
||||
case Stmt::CXXParenListInitExprClass:
|
||||
K = CXCursor_CXXParenListInitExpr;
|
||||
break;
|
||||
|
||||
case Stmt::MSDependentExistsStmtClass:
|
||||
K = CXCursor_UnexposedStmt;
|
||||
break;
|
||||
|
||||
@ -1156,7 +1156,7 @@ code. This issue is expected to be rectified soon.
|
||||
<tr>
|
||||
<td rowspan="2">Parenthesized initialization of aggregates</td>
|
||||
<td><a href="https://wg21.link/p0960r3">P0960R3</a></td>
|
||||
<td rowspan="2" class="unreleased" align="center">Clang 16</td>
|
||||
<td rowspan="2" class="none" align="center">No</td>
|
||||
</tr>
|
||||
<tr> <!-- from Belfast -->
|
||||
<td><a href="https://wg21.link/p1975r0">P1975R0</a></td>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user