[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:
Alan Zhao 2023-01-04 14:54:55 -08:00
parent 45f347270c
commit 4e02ff2303
43 changed files with 83 additions and 1291 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -914,10 +914,7 @@ public:
CallInit,
/// Direct list-initialization (C++11)
ListInit,
/// Parenthesized list-initialization (C++20)
ParenListInit
ListInit
};
/// Kinds of thread-local storage.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -451,7 +451,6 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
case InitializationSequence::FK_ConstructorOverloadFailed:
case InitializationSequence::FK_UserConversionOverloadFailed:
case InitializationSequence::FK_ParenthesizedListInitFailed:
break;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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