aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaInit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaInit.cpp')
-rw-r--r--clang/lib/Sema/SemaInit.cpp980
1 files changed, 654 insertions, 326 deletions
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index ddb2b5cf5cd1..32c9215184eb 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -20,12 +20,16 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Designator.h"
+#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@@ -139,6 +143,9 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT,
if (IsWideCharCompatible(ElemTy, Context))
return SIF_IncompatWideStringIntoWideChar;
return SIF_Other;
+ case StringLiteral::Unevaluated:
+ assert(false && "Unevaluated string literal in initialization");
+ break;
}
llvm_unreachable("missed a StringLiteral kind?");
@@ -173,6 +180,8 @@ static void updateStringLiteralType(Expr *E, QualType Ty) {
E = GSE->getResultExpr();
} else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) {
E = CE->getChosenSubExpr();
+ } else if (PredefinedExpr *PE = dyn_cast<PredefinedExpr>(E)) {
+ E = PE->getFunctionName();
} else {
llvm_unreachable("unexpected expr in string literal init");
}
@@ -301,6 +310,7 @@ class InitListChecker {
bool InOverloadResolution;
InitListExpr *FullyStructuredList = nullptr;
NoInitExpr *DummyExpr = nullptr;
+ SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes = nullptr;
NoInitExpr *getDummyInit() {
if (!DummyExpr)
@@ -350,7 +360,7 @@ class InitListChecker {
unsigned &StructuredIndex);
void CheckStructUnionTypes(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
- CXXRecordDecl::base_class_range Bases,
+ CXXRecordDecl::base_class_const_range Bases,
RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
@@ -387,18 +397,22 @@ class InitListChecker {
unsigned ExpectedNumInits);
int numArrayElements(QualType DeclType);
int numStructUnionElements(QualType DeclType);
+ static RecordDecl *getRecordDecl(QualType DeclType);
ExprResult PerformEmptyInit(SourceLocation Loc,
const InitializedEntity &Entity);
/// Diagnose that OldInit (or part thereof) has been overridden by NewInit.
void diagnoseInitOverride(Expr *OldInit, SourceRange NewInitRange,
+ bool UnionOverride = false,
bool FullyOverwritten = true) {
// Overriding an initializer via a designator is valid with C99 designated
// initializers, but ill-formed with C++20 designated initializers.
- unsigned DiagID = SemaRef.getLangOpts().CPlusPlus
- ? diag::ext_initializer_overrides
- : diag::warn_initializer_overrides;
+ unsigned DiagID =
+ SemaRef.getLangOpts().CPlusPlus
+ ? (UnionOverride ? diag::ext_initializer_union_overrides
+ : diag::ext_initializer_overrides)
+ : diag::warn_initializer_overrides;
if (InOverloadResolution && SemaRef.getLangOpts().CPlusPlus) {
// In overload resolution, we have to strictly enforce the rules, and so
@@ -486,9 +500,19 @@ class InitListChecker {
SourceLocation Loc);
public:
+ InitListChecker(
+ Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T,
+ bool VerifyOnly, bool TreatUnavailableAsInvalid,
+ bool InOverloadResolution = false,
+ SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes = nullptr);
InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL,
- QualType &T, bool VerifyOnly, bool TreatUnavailableAsInvalid,
- bool InOverloadResolution = false);
+ QualType &T,
+ SmallVectorImpl<QualType> &AggrDeductionCandidateParamTypes)
+ : InitListChecker(S, Entity, IL, T, /*VerifyOnly=*/true,
+ /*TreatUnavailableAsInvalid=*/false,
+ /*InOverloadResolution=*/false,
+ &AggrDeductionCandidateParamTypes){};
+
bool HadError() { return hadError; }
// Retrieves the fully-structured initializer list used for
@@ -805,7 +829,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
// order to leave them uninitialized, the ILE is expanded and the extra
// fields are then filled with NoInitExpr.
unsigned NumElems = numStructUnionElements(ILE->getType());
- if (RDecl->hasFlexibleArrayMember())
+ if (!RDecl->isUnion() && RDecl->hasFlexibleArrayMember())
++NumElems;
if (!VerifyOnly && ILE->getNumInits() < NumElems)
ILE->resizeInits(SemaRef.Context, NumElems);
@@ -948,18 +972,19 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
static bool hasAnyDesignatedInits(const InitListExpr *IL) {
for (const Stmt *Init : *IL)
- if (Init && isa<DesignatedInitExpr>(Init))
+ if (isa_and_nonnull<DesignatedInitExpr>(Init))
return true;
return false;
}
-InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T, bool VerifyOnly,
- bool TreatUnavailableAsInvalid,
- bool InOverloadResolution)
+InitListChecker::InitListChecker(
+ Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T,
+ bool VerifyOnly, bool TreatUnavailableAsInvalid, bool InOverloadResolution,
+ SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes)
: SemaRef(S), VerifyOnly(VerifyOnly),
TreatUnavailableAsInvalid(TreatUnavailableAsInvalid),
- InOverloadResolution(InOverloadResolution) {
+ InOverloadResolution(InOverloadResolution),
+ AggrDeductionCandidateParamTypes(AggrDeductionCandidateParamTypes) {
if (!VerifyOnly || hasAnyDesignatedInits(IL)) {
FullyStructuredList =
createInitListExpr(T, IL->getSourceRange(), IL->getNumInits());
@@ -973,7 +998,7 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
CheckExplicitInitList(Entity, IL, T, FullyStructuredList,
/*TopLevelObject=*/true);
- if (!hadError && FullyStructuredList) {
+ if (!hadError && !AggrDeductionCandidateParamTypes && FullyStructuredList) {
bool RequiresSecondPass = false;
FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass,
/*OuterILE=*/nullptr, /*OuterIndex=*/0);
@@ -1009,6 +1034,14 @@ int InitListChecker::numStructUnionElements(QualType DeclType) {
return InitializableMembers - structDecl->hasFlexibleArrayMember();
}
+RecordDecl *InitListChecker::getRecordDecl(QualType DeclType) {
+ if (const auto *RT = DeclType->getAs<RecordType>())
+ return RT->getDecl();
+ if (const auto *Inject = DeclType->getAs<InjectedClassNameType>())
+ return Inject->getDecl();
+ return nullptr;
+}
+
/// Determine whether Entity is an entity for which it is idiomatic to elide
/// the braces in aggregate initialization.
static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) {
@@ -1152,6 +1185,7 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity,
case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_TemplateParameter:
case InitializedEntity::EK_Result:
+ case InitializedEntity::EK_ParenAggInitMember:
// Extra braces here are suspicious.
DiagID = diag::warn_braces_around_init;
break;
@@ -1302,15 +1336,18 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
} else if (DeclType->isVectorType()) {
CheckVectorType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
- } else if (DeclType->isRecordType()) {
- assert(DeclType->isAggregateType() &&
- "non-aggregate records should be handed in CheckSubElementType");
- RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
+ } else if (const RecordDecl *RD = getRecordDecl(DeclType)) {
auto Bases =
- CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(),
- CXXRecordDecl::base_class_iterator());
- if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- Bases = CXXRD->bases();
+ CXXRecordDecl::base_class_const_range(CXXRecordDecl::base_class_const_iterator(),
+ CXXRecordDecl::base_class_const_iterator());
+ if (DeclType->isRecordType()) {
+ assert(DeclType->isAggregateType() &&
+ "non-aggregate records should be handed in CheckSubElementType");
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+ Bases = CXXRD->bases();
+ } else {
+ Bases = cast<CXXRecordDecl>(RD)->bases();
+ }
CheckStructUnionTypes(Entity, IList, DeclType, Bases, RD->field_begin(),
SubobjectIsDesignatorContext, Index, StructuredList,
StructuredIndex, TopLevelObject);
@@ -1340,6 +1377,13 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
// Checks for scalar type are sufficient for these types too.
CheckScalarType(Entity, IList, DeclType, Index, StructuredList,
StructuredIndex);
+ } else if (DeclType->isDependentType()) {
+ // C++ [over.match.class.deduct]p1.5:
+ // brace elision is not considered for any aggregate element that has a
+ // dependent non-array type or an array type with a value-dependent bound
+ ++Index;
+ assert(AggrDeductionCandidateParamTypes);
+ AggrDeductionCandidateParamTypes->push_back(DeclType);
} else {
if (!VerifyOnly)
SemaRef.Diag(IList->getBeginLoc(), diag::err_illegal_initializer_type)
@@ -1397,31 +1441,46 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
? InitializedEntity::InitializeTemporary(ElemType)
: Entity;
- InitializationSequence Seq(SemaRef, TmpEntity, Kind, expr,
- /*TopLevelOfInitList*/ true);
+ if (TmpEntity.getType()->isDependentType()) {
+ // C++ [over.match.class.deduct]p1.5:
+ // brace elision is not considered for any aggregate element that has a
+ // dependent non-array type or an array type with a value-dependent
+ // bound
+ assert(AggrDeductionCandidateParamTypes);
+ if (!isa_and_nonnull<ConstantArrayType>(
+ SemaRef.Context.getAsArrayType(ElemType))) {
+ ++Index;
+ AggrDeductionCandidateParamTypes->push_back(ElemType);
+ return;
+ }
+ } else {
+ InitializationSequence Seq(SemaRef, TmpEntity, Kind, expr,
+ /*TopLevelOfInitList*/ true);
+ // C++14 [dcl.init.aggr]p13:
+ // If the assignment-expression can initialize a member, the member is
+ // initialized. Otherwise [...] brace elision is assumed
+ //
+ // Brace elision is never performed if the element is not an
+ // assignment-expression.
+ if (Seq || isa<InitListExpr>(expr)) {
+ if (!VerifyOnly) {
+ ExprResult Result = Seq.Perform(SemaRef, TmpEntity, Kind, expr);
+ if (Result.isInvalid())
+ hadError = true;
- // C++14 [dcl.init.aggr]p13:
- // If the assignment-expression can initialize a member, the member is
- // initialized. Otherwise [...] brace elision is assumed
- //
- // Brace elision is never performed if the element is not an
- // assignment-expression.
- if (Seq || isa<InitListExpr>(expr)) {
- if (!VerifyOnly) {
- ExprResult Result = Seq.Perform(SemaRef, TmpEntity, Kind, expr);
- if (Result.isInvalid())
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ Result.getAs<Expr>());
+ } else if (!Seq) {
hadError = true;
-
- UpdateStructuredListElement(StructuredList, StructuredIndex,
- Result.getAs<Expr>());
- } else if (!Seq) {
- hadError = true;
- } else if (StructuredList) {
- UpdateStructuredListElement(StructuredList, StructuredIndex,
- getDummyInit());
+ } else if (StructuredList) {
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ getDummyInit());
+ }
+ ++Index;
+ if (AggrDeductionCandidateParamTypes)
+ AggrDeductionCandidateParamTypes->push_back(ElemType);
+ return;
}
- ++Index;
- return;
}
// Fall through for subaggregate initialization
@@ -1536,7 +1595,7 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity,
// the element type of the complex type. The first element initializes
// the real part, and the second element intitializes the imaginary part.
- if (IList->getNumInits() != 2)
+ if (IList->getNumInits() < 2)
return CheckScalarType(Entity, IList, DeclType, Index, StructuredList,
StructuredIndex);
@@ -1565,20 +1624,23 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
unsigned &StructuredIndex) {
if (Index >= IList->getNumInits()) {
if (!VerifyOnly) {
- if (DeclType->isSizelessBuiltinType())
- SemaRef.Diag(IList->getBeginLoc(),
- SemaRef.getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_empty_sizeless_initializer
- : diag::err_empty_sizeless_initializer)
- << DeclType << IList->getSourceRange();
- else
- SemaRef.Diag(IList->getBeginLoc(),
- SemaRef.getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_empty_scalar_initializer
- : diag::err_empty_scalar_initializer)
- << IList->getSourceRange();
+ if (SemaRef.getLangOpts().CPlusPlus) {
+ if (DeclType->isSizelessBuiltinType())
+ SemaRef.Diag(IList->getBeginLoc(),
+ SemaRef.getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_empty_sizeless_initializer
+ : diag::err_empty_sizeless_initializer)
+ << DeclType << IList->getSourceRange();
+ else
+ SemaRef.Diag(IList->getBeginLoc(),
+ SemaRef.getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_empty_scalar_initializer
+ : diag::err_empty_scalar_initializer)
+ << IList->getSourceRange();
+ }
}
- hadError = !SemaRef.getLangOpts().CPlusPlus11;
+ hadError =
+ SemaRef.getLangOpts().CPlusPlus && !SemaRef.getLangOpts().CPlusPlus11;
++Index;
++StructuredIndex;
return;
@@ -1634,6 +1696,8 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
}
UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr);
++Index;
+ if (AggrDeductionCandidateParamTypes)
+ AggrDeductionCandidateParamTypes->push_back(DeclType);
}
void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
@@ -1689,6 +1753,8 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
+ if (AggrDeductionCandidateParamTypes)
+ AggrDeductionCandidateParamTypes->push_back(DeclType);
}
void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
@@ -1740,6 +1806,8 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
}
UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr);
++Index;
+ if (AggrDeductionCandidateParamTypes)
+ AggrDeductionCandidateParamTypes->push_back(elementType);
return;
}
@@ -1901,6 +1969,8 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
StructuredList->resizeInits(SemaRef.Context, StructuredIndex);
}
++Index;
+ if (AggrDeductionCandidateParamTypes)
+ AggrDeductionCandidateParamTypes->push_back(DeclType);
return;
}
}
@@ -1908,11 +1978,24 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
// Check for VLAs; in standard C it would be possible to check this
// earlier, but I don't know where clang accepts VLAs (gcc accepts
// them in all sorts of strange places).
- if (!VerifyOnly)
- SemaRef.Diag(VAT->getSizeExpr()->getBeginLoc(),
- diag::err_variable_object_no_init)
- << VAT->getSizeExpr()->getSourceRange();
- hadError = true;
+ bool HasErr = IList->getNumInits() != 0 || SemaRef.getLangOpts().CPlusPlus;
+ if (!VerifyOnly) {
+ // C2x 6.7.9p4: An entity of variable length array type shall not be
+ // initialized except by an empty initializer.
+ //
+ // The C extension warnings are issued from ParseBraceInitializer() and
+ // do not need to be issued here. However, we continue to issue an error
+ // in the case there are initializers or we are compiling C++. We allow
+ // use of VLAs in C++, but it's not clear we want to allow {} to zero
+ // init a VLA in C++ in all cases (such as with non-trivial constructors).
+ // FIXME: should we allow this construct in C++ when it makes sense to do
+ // so?
+ if (HasErr)
+ SemaRef.Diag(VAT->getSizeExpr()->getBeginLoc(),
+ diag::err_variable_object_no_init)
+ << VAT->getSizeExpr()->getSourceRange();
+ }
+ hadError = HasErr;
++Index;
++StructuredIndex;
return;
@@ -2043,24 +2126,22 @@ bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity,
void InitListChecker::CheckStructUnionTypes(
const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType,
- CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field,
+ CXXRecordDecl::base_class_const_range Bases, RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList, unsigned &StructuredIndex,
bool TopLevelObject) {
- RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl();
+ const RecordDecl *RD = getRecordDecl(DeclType);
// If the record is invalid, some of it's members are invalid. To avoid
// confusion, we forgo checking the initializer for the entire record.
- if (structDecl->isInvalidDecl()) {
+ if (RD->isInvalidDecl()) {
// Assume it was supposed to consume a single initializer.
++Index;
hadError = true;
return;
}
- if (DeclType->isUnionType() && IList->getNumInits() == 0) {
- RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
-
+ if (RD->isUnion() && IList->getNumInits() == 0) {
if (!VerifyOnly)
for (FieldDecl *FD : RD->fields()) {
QualType ET = SemaRef.Context.getBaseElementType(FD->getType());
@@ -2104,7 +2185,8 @@ void InitListChecker::CheckStructUnionTypes(
bool InitializedSomething = false;
// If we have any base classes, they are initialized prior to the fields.
- for (auto &Base : Bases) {
+ for (auto I = Bases.begin(), E = Bases.end(); I != E; ++I) {
+ auto &Base = *I;
Expr *Init = Index < IList->getNumInits() ? IList->getInit(Index) : nullptr;
// Designated inits always initialize fields, so if we see one, all
@@ -2112,6 +2194,34 @@ void InitListChecker::CheckStructUnionTypes(
if (Init && isa<DesignatedInitExpr>(Init))
Init = nullptr;
+ // C++ [over.match.class.deduct]p1.6:
+ // each non-trailing aggregate element that is a pack expansion is assumed
+ // to correspond to no elements of the initializer list, and (1.7) a
+ // trailing aggregate element that is a pack expansion is assumed to
+ // correspond to all remaining elements of the initializer list (if any).
+
+ // C++ [over.match.class.deduct]p1.9:
+ // ... except that additional parameter packs of the form P_j... are
+ // inserted into the parameter list in their original aggregate element
+ // position corresponding to each non-trailing aggregate element of
+ // type P_j that was skipped because it was a parameter pack, and the
+ // trailing sequence of parameters corresponding to a trailing
+ // aggregate element that is a pack expansion (if any) is replaced
+ // by a single parameter of the form T_n....
+ if (AggrDeductionCandidateParamTypes && Base.isPackExpansion()) {
+ AggrDeductionCandidateParamTypes->push_back(
+ SemaRef.Context.getPackExpansionType(Base.getType(), std::nullopt));
+
+ // Trailing pack expansion
+ if (I + 1 == E && RD->field_empty()) {
+ if (Index < IList->getNumInits())
+ Index = IList->getNumInits();
+ return;
+ }
+
+ continue;
+ }
+
SourceLocation InitLoc = Init ? Init->getBeginLoc() : IList->getEndLoc();
InitializedEntity BaseEntity = InitializedEntity::InitializeBase(
SemaRef.Context, &Base, false, &Entity);
@@ -2134,7 +2244,6 @@ void InitListChecker::CheckStructUnionTypes(
// anything except look at designated initializers; That's okay,
// because an error should get printed out elsewhere. It might be
// worthwhile to skip over the rest of the initializer, though.
- RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) {
return isa<FieldDecl>(D) || isa<RecordDecl>(D);
@@ -2218,7 +2327,7 @@ void InitListChecker::CheckStructUnionTypes(
}
// We've already initialized a member of a union. We're done.
- if (InitializedSomething && DeclType->isUnionType())
+ if (InitializedSomething && RD->isUnion())
break;
// If we've hit the flexible array member at the end, we're done.
@@ -2259,7 +2368,7 @@ void InitListChecker::CheckStructUnionTypes(
StructuredList, StructuredIndex);
InitializedSomething = true;
- if (DeclType->isUnionType() && StructuredList) {
+ if (RD->isUnion() && StructuredList) {
// Initialize the first field within the union.
StructuredList->setInitializedFieldInUnion(*Field);
}
@@ -2270,7 +2379,7 @@ void InitListChecker::CheckStructUnionTypes(
// Emit warnings for missing struct field initializers.
if (!VerifyOnly && InitializedSomething && CheckForMissingFields &&
Field != FieldEnd && !Field->getType()->isIncompleteArrayType() &&
- !DeclType->isUnionType()) {
+ !RD->isUnion()) {
// It is possible we have one or more unnamed bitfields remaining.
// Find first (if any) named field and emit warning.
for (RecordDecl::field_iterator it = Field, end = RD->field_end();
@@ -2285,7 +2394,7 @@ void InitListChecker::CheckStructUnionTypes(
// Check that any remaining fields can be value-initialized if we're not
// building a structured list. (If we are, we'll check this later.)
- if (!StructuredList && Field != FieldEnd && !DeclType->isUnionType() &&
+ if (!StructuredList && Field != FieldEnd && !RD->isUnion() &&
!Field->getType()->isIncompleteArrayType()) {
for (; Field != FieldEnd && !hadError; ++Field) {
if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer())
@@ -2324,7 +2433,8 @@ void InitListChecker::CheckStructUnionTypes(
InitializedEntity MemberEntity =
InitializedEntity::InitializeMember(*Field, &Entity);
- if (isa<InitListExpr>(IList->getInit(Index)))
+ if (isa<InitListExpr>(IList->getInit(Index)) ||
+ AggrDeductionCandidateParamTypes)
CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
StructuredList, StructuredIndex);
else
@@ -2347,14 +2457,14 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
for (IndirectFieldDecl::chain_iterator PI = IndirectField->chain_begin(),
PE = IndirectField->chain_end(); PI != PE; ++PI) {
if (PI + 1 == PE)
- Replacements.push_back(Designator((IdentifierInfo *)nullptr,
- DIE->getDesignator(DesigIdx)->getDotLoc(),
- DIE->getDesignator(DesigIdx)->getFieldLoc()));
+ Replacements.push_back(Designator::CreateFieldDesignator(
+ (IdentifierInfo *)nullptr, DIE->getDesignator(DesigIdx)->getDotLoc(),
+ DIE->getDesignator(DesigIdx)->getFieldLoc()));
else
- Replacements.push_back(Designator((IdentifierInfo *)nullptr,
- SourceLocation(), SourceLocation()));
+ Replacements.push_back(Designator::CreateFieldDesignator(
+ (IdentifierInfo *)nullptr, SourceLocation(), SourceLocation()));
assert(isa<FieldDecl>(*PI));
- Replacements.back().setField(cast<FieldDecl>(*PI));
+ Replacements.back().setFieldDecl(cast<FieldDecl>(*PI));
}
// Expand the current designator into the set of replacement
@@ -2382,7 +2492,7 @@ namespace {
// the given struct or union.
class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
public:
- explicit FieldInitializerValidatorCCC(RecordDecl *RD)
+ explicit FieldInitializerValidatorCCC(const RecordDecl *RD)
: Record(RD) {}
bool ValidateCandidate(const TypoCorrection &candidate) override {
@@ -2395,7 +2505,7 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
}
private:
- RecordDecl *Record;
+ const RecordDecl *Record;
};
} // end anonymous namespace
@@ -2471,6 +2581,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
Result.get());
}
++Index;
+ if (AggrDeductionCandidateParamTypes)
+ AggrDeductionCandidateParamTypes->push_back(CurrentObjectType);
return !Seq;
}
@@ -2528,6 +2640,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// subobject [0].b.
diagnoseInitOverride(ExistingInit,
SourceRange(D->getBeginLoc(), DIE->getEndLoc()),
+ /*UnionOverride=*/false,
/*FullyOverwritten=*/false);
if (!VerifyOnly) {
@@ -2563,8 +2676,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// then the current object (defined below) shall have
// structure or union type and the identifier shall be the
// name of a member of that type.
- const RecordType *RT = CurrentObjectType->getAs<RecordType>();
- if (!RT) {
+ RecordDecl *RD = getRecordDecl(CurrentObjectType);
+ if (!RD) {
SourceLocation Loc = D->getDotLoc();
if (Loc.isInvalid())
Loc = D->getFieldLoc();
@@ -2575,10 +2688,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
return true;
}
- FieldDecl *KnownField = D->getField();
+ FieldDecl *KnownField = D->getFieldDecl();
if (!KnownField) {
- IdentifierInfo *FieldName = D->getFieldName();
- DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
+ const IdentifierInfo *FieldName = D->getFieldName();
+ DeclContext::lookup_result Lookup = RD->lookup(FieldName);
for (NamedDecl *ND : Lookup) {
if (auto *FD = dyn_cast<FieldDecl>(ND)) {
KnownField = FD;
@@ -2612,11 +2725,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Name lookup didn't find anything.
// Determine whether this was a typo for another field name.
- FieldInitializerValidatorCCC CCC(RT->getDecl());
+ FieldInitializerValidatorCCC CCC(RD);
if (TypoCorrection Corrected = SemaRef.CorrectTypo(
DeclarationNameInfo(FieldName, D->getFieldLoc()),
Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr, CCC,
- Sema::CTK_ErrorRecovery, RT->getDecl())) {
+ Sema::CTK_ErrorRecovery, RD)) {
SemaRef.diagnoseTypo(
Corrected,
SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
@@ -2625,8 +2738,15 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
hadError = true;
} else {
// Typo correction didn't find anything.
- SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
- << FieldName << CurrentObjectType;
+ SourceLocation Loc = D->getFieldLoc();
+
+ // The loc can be invalid with a "null" designator (i.e. an anonymous
+ // union/struct). Do our best to approximate the location.
+ if (Loc.isInvalid())
+ Loc = IList->getBeginLoc();
+
+ SemaRef.Diag(Loc, diag::err_field_designator_unknown)
+ << FieldName << CurrentObjectType << DIE->getSourceRange();
++Index;
return true;
}
@@ -2634,12 +2754,12 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
}
unsigned NumBases = 0;
- if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
NumBases = CXXRD->getNumBases();
unsigned FieldIndex = NumBases;
- for (auto *FI : RT->getDecl()->fields()) {
+ for (auto *FI : RD->fields()) {
if (FI->isUnnamedBitfield())
continue;
if (declaresSameEntity(KnownField, FI)) {
@@ -2654,7 +2774,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// All of the fields of a union are located at the same place in
// the initializer list.
- if (RT->getDecl()->isUnion()) {
+ if (RD->isUnion()) {
FieldIndex = 0;
if (StructuredList) {
FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion();
@@ -2666,7 +2786,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
if (ExistingInit) {
// We're about to throw away an initializer, emit warning.
diagnoseInitOverride(
- ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc()));
+ ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc()),
+ /*UnionOverride=*/true,
+ /*FullyOverwritten=*/SemaRef.getLangOpts().CPlusPlus ? false
+ : true);
}
// remove existing initializer
@@ -2706,15 +2829,14 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// cases where a designator takes us backwards too.
if (IsFirstDesignator && !VerifyOnly && SemaRef.getLangOpts().CPlusPlus &&
NextField &&
- (*NextField == RT->getDecl()->field_end() ||
+ (*NextField == RD->field_end() ||
(*NextField)->getFieldIndex() > Field->getFieldIndex() + 1)) {
// Find the field that we just initialized.
FieldDecl *PrevField = nullptr;
- for (auto FI = RT->getDecl()->field_begin();
- FI != RT->getDecl()->field_end(); ++FI) {
+ for (auto FI = RD->field_begin(); FI != RD->field_end(); ++FI) {
if (FI->isUnnamedBitfield())
continue;
- if (*NextField != RT->getDecl()->field_end() &&
+ if (*NextField != RD->field_end() &&
declaresSameEntity(*FI, **NextField))
break;
PrevField = *FI;
@@ -2725,7 +2847,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
SemaRef.Diag(DIE->getBeginLoc(), diag::ext_designated_init_reordered)
<< KnownField << PrevField << DIE->getSourceRange();
- unsigned OldIndex = NumBases + PrevField->getFieldIndex();
+ unsigned OldIndex = StructuredIndex - 1;
if (StructuredList && OldIndex <= StructuredList->getNumInits()) {
if (Expr *PrevInit = StructuredList->getInit(OldIndex)) {
SemaRef.Diag(PrevInit->getBeginLoc(),
@@ -2739,7 +2861,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Update the designator with the field declaration.
if (!VerifyOnly)
- D->setField(*Field);
+ D->setFieldDecl(*Field);
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this field.
@@ -2829,8 +2951,12 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// If this the first designator, our caller will continue checking
// the rest of this struct/class/union subobject.
if (IsFirstDesignator) {
+ if (Field != RD->field_end() && Field->isUnnamedBitfield())
+ ++Field;
+
if (NextField)
*NextField = Field;
+
StructuredIndex = FieldIndex;
return false;
}
@@ -2839,7 +2965,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
return false;
// We've already initialized something in the union; we're done.
- if (RT->getDecl()->isUnion())
+ if (RD->isUnion())
return hadError;
// Check the remaining fields within this class/struct/union subobject.
@@ -3147,6 +3273,8 @@ InitListChecker::createInitListExpr(QualType CurrentObjectType,
NumElements = VType->getNumElements();
} else if (CurrentObjectType->isRecordType()) {
NumElements = numStructUnionElements(CurrentObjectType);
+ } else if (CurrentObjectType->isDependentType()) {
+ NumElements = 1;
}
Result->reserveInits(SemaRef.Context, NumElements);
@@ -3225,13 +3353,11 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
// Build designators and check array designator expressions.
for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) {
const Designator &D = Desig.getDesignator(Idx);
- switch (D.getKind()) {
- case Designator::FieldDesignator:
- Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(),
- D.getFieldLoc()));
- break;
- case Designator::ArrayDesignator: {
+ if (D.isFieldDesignator()) {
+ Designators.push_back(ASTDesignator::CreateFieldDesignator(
+ D.getFieldDecl(), D.getDotLoc(), D.getFieldLoc()));
+ } else if (D.isArrayDesignator()) {
Expr *Index = static_cast<Expr *>(D.getArrayIndex());
llvm::APSInt IndexValue;
if (!Index->isTypeDependent() && !Index->isValueDependent())
@@ -3239,15 +3365,11 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
if (!Index)
Invalid = true;
else {
- Designators.push_back(ASTDesignator(InitExpressions.size(),
- D.getLBracketLoc(),
- D.getRBracketLoc()));
+ Designators.push_back(ASTDesignator::CreateArrayDesignator(
+ InitExpressions.size(), D.getLBracketLoc(), D.getRBracketLoc()));
InitExpressions.push_back(Index);
}
- break;
- }
-
- case Designator::ArrayRangeDesignator: {
+ } else if (D.isArrayRangeDesignator()) {
Expr *StartIndex = static_cast<Expr *>(D.getArrayRangeStart());
Expr *EndIndex = static_cast<Expr *>(D.getArrayRangeEnd());
llvm::APSInt StartValue;
@@ -3279,25 +3401,19 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
<< StartIndex->getSourceRange() << EndIndex->getSourceRange();
Invalid = true;
} else {
- Designators.push_back(ASTDesignator(InitExpressions.size(),
- D.getLBracketLoc(),
- D.getEllipsisLoc(),
- D.getRBracketLoc()));
+ Designators.push_back(ASTDesignator::CreateArrayRangeDesignator(
+ InitExpressions.size(), D.getLBracketLoc(), D.getEllipsisLoc(),
+ D.getRBracketLoc()));
InitExpressions.push_back(StartIndex);
InitExpressions.push_back(EndIndex);
}
}
- break;
- }
}
}
if (Invalid || Init.isInvalid())
return ExprError();
- // Clear out the expressions within the designation.
- Desig.ClearExprs(*this);
-
return DesignatedInitExpr::Create(Context, Designators, InitExpressions,
EqualOrColonLoc, GNUSyntax,
Init.getAs<Expr>());
@@ -3348,6 +3464,7 @@ DeclarationName InitializedEntity::getName() const {
case EK_Variable:
case EK_Member:
+ case EK_ParenAggInitMember:
case EK_Binding:
case EK_TemplateParameter:
return Variable.VariableOrMember->getDeclName();
@@ -3379,6 +3496,7 @@ ValueDecl *InitializedEntity::getDecl() const {
switch (getKind()) {
case EK_Variable:
case EK_Member:
+ case EK_ParenAggInitMember:
case EK_Binding:
case EK_TemplateParameter:
return Variable.VariableOrMember;
@@ -3420,6 +3538,7 @@ bool InitializedEntity::allowsNRVO() const {
case EK_Parameter_CF_Audited:
case EK_TemplateParameter:
case EK_Member:
+ case EK_ParenAggInitMember:
case EK_Binding:
case EK_New:
case EK_Temporary:
@@ -3454,7 +3573,10 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
case EK_Result: OS << "Result"; break;
case EK_StmtExprResult: OS << "StmtExprResult"; break;
case EK_Exception: OS << "Exception"; break;
- case EK_Member: OS << "Member"; break;
+ case EK_Member:
+ case EK_ParenAggInitMember:
+ OS << "Member";
+ break;
case EK_Binding: OS << "Binding"; break;
case EK_New: OS << "New"; break;
case EK_Temporary: OS << "Temporary"; break;
@@ -3591,6 +3713,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_ExplicitConstructor:
case FK_AddressOfUnaddressableFunction:
case FK_ParenthesizedListInitFailed:
+ case FK_DesignatedInitForNonAggregate:
return false;
case FK_ReferenceInitOverloadFailed:
@@ -4428,6 +4551,22 @@ static void TryListInitialization(Sema &S,
return;
}
+ // C++20 [dcl.init.list]p3:
+ // - If the braced-init-list contains a designated-initializer-list, T shall
+ // be an aggregate class. [...] Aggregate initialization is performed.
+ //
+ // We allow arrays here too in order to support array designators.
+ //
+ // FIXME: This check should precede the handling of reference initialization.
+ // We follow other compilers in allowing things like 'Aggr &&a = {.x = 1};'
+ // as a tentative DR resolution.
+ bool IsDesignatedInit = InitList->hasDesignatedInit();
+ if (!DestType->isAggregateType() && IsDesignatedInit) {
+ Sequence.SetFailed(
+ InitializationSequence::FK_DesignatedInitForNonAggregate);
+ return;
+ }
+
// C++11 [dcl.init.list]p3, per DR1467:
// - If T is a class type and the initializer list has a single element of
// type cv U, where U is T or a class derived from T, the object is
@@ -4439,7 +4578,8 @@ static void TryListInitialization(Sema &S,
// (8.5.2 [dcl.init.string]), initialization is performed as described
// in that section.
// - Otherwise, if T is an aggregate, [...] (continue below).
- if (S.getLangOpts().CPlusPlus11 && InitList->getNumInits() == 1) {
+ if (S.getLangOpts().CPlusPlus11 && InitList->getNumInits() == 1 &&
+ !IsDesignatedInit) {
if (DestType->isRecordType()) {
QualType InitType = InitList->getInit(0)->getType();
if (S.Context.hasSameUnqualifiedType(InitType, DestType) ||
@@ -4481,7 +4621,7 @@ static void TryListInitialization(Sema &S,
// - If T is an aggregate, aggregate initialization is performed.
if ((DestType->isRecordType() && !DestType->isAggregateType()) ||
(S.getLangOpts().CPlusPlus11 &&
- S.isStdInitializerList(DestType, nullptr))) {
+ S.isStdInitializerList(DestType, nullptr) && !IsDesignatedInit)) {
if (S.getLangOpts().CPlusPlus11) {
// - Otherwise, if the initializer list has no elements and T is a
// class type with a default constructor, the object is
@@ -5274,176 +5414,225 @@ static void TryOrBuildParenListInitialization(
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
ArrayRef<Expr *> Args, InitializationSequence &Sequence, bool VerifyOnly,
ExprResult *Result = nullptr) {
- unsigned ArgIndexToProcess = 0;
+ unsigned EntityIndexToProcess = 0;
SmallVector<Expr *, 4> InitExprs;
QualType ResultType;
Expr *ArrayFiller = nullptr;
FieldDecl *InitializedFieldInUnion = 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 {
- bool IsUnionType = Entity.getType()->isUnionType();
- 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 && IsUnionType)
- return true;
-
- bool IsMember = SubEntity.getKind() == InitializedEntity::EK_Member;
-
- // Unnamed bitfields should not be initialized at all, either with an arg
- // or by default.
- if (IsMember && 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 (IsMember) {
- 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);
+ auto HandleInitializedEntity = [&](const InitializedEntity &SubEntity,
+ const InitializationKind &SubKind,
+ Expr *Arg, Expr **InitExpr = nullptr) {
+ InitializationSequence IS = [&]() {
+ if (Arg)
+ return InitializationSequence(S, SubEntity, SubKind, Arg);
+ return InitializationSequence(S, SubEntity, SubKind, std::nullopt);
+ }();
- return false;
- }
- if (!VerifyOnly) {
- ExprResult ER = SubSeq.Perform(S, SubEntity, SubKind, E);
- InitExprs.push_back(ER.get());
- if (IsMember && IsUnionType)
- InitializedFieldInUnion = cast<FieldDecl>(SubEntity.getDecl());
- }
+ if (IS.Failed()) {
+ if (!VerifyOnly) {
+ if (Arg)
+ IS.Diagnose(S, SubEntity, SubKind, Arg);
+ else
+ IS.Diagnose(S, SubEntity, SubKind, std::nullopt);
} else {
- // We've processed all of the args, but there are still entities that
- // have to be initialized.
- if (IsMember) {
- // 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());
- }
+ Sequence.SetFailed(
+ InitializationSequence::FK_ParenthesizedListInitFailed);
}
+
+ return false;
+ }
+ if (!VerifyOnly) {
+ ExprResult ER;
+ if (Arg)
+ ER = IS.Perform(S, SubEntity, SubKind, Arg);
+ else
+ ER = IS.Perform(S, SubEntity, SubKind, std::nullopt);
+ if (InitExpr)
+ *InitExpr = ER.get();
+ else
+ 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
+ // C++ [dcl.init]p16.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
+ // the destination type is an array of unknown bound, it is defined as
// having k elements.
if (const ConstantArrayType *CAT =
- S.getASTContext().getAsConstantArrayType(Entity.getType()))
+ S.getASTContext().getAsConstantArrayType(Entity.getType())) {
ArrayLength = CAT->getSize().getZExtValue();
- else
+ ResultType = Entity.getType();
+ } else if (const VariableArrayType *VAT =
+ S.getASTContext().getAsVariableArrayType(Entity.getType())) {
+ // Braced-initialization of variable array types is not allowed, even if
+ // the size is greater than or equal to the number of args, so we don't
+ // allow them to be initialized via parenthesized aggregate initialization
+ // either.
+ const Expr *SE = VAT->getSizeExpr();
+ S.Diag(SE->getBeginLoc(), diag::err_variable_object_no_init)
+ << SE->getSourceRange();
+ return;
+ } else {
+ assert(isa<IncompleteArrayType>(Entity.getType()));
ArrayLength = Args.size();
+ }
+ EntityIndexToProcess = ArrayLength;
- if (ArrayLength >= Args.size()) {
- for (uint64_t I = 0; I < ArrayLength; ++I)
- ElementEntities.push_back(
- InitializedEntity::InitializeElement(S.getASTContext(), I, Entity));
-
- if (!ProcessEntities(ElementEntities))
+ // ...the ith array element is copy-initialized with xi for each
+ // 1 <= i <= k
+ for (Expr *E : Args) {
+ InitializedEntity SubEntity = InitializedEntity::InitializeElement(
+ S.getASTContext(), EntityIndexToProcess, Entity);
+ InitializationKind SubKind = InitializationKind::CreateForInit(
+ E->getExprLoc(), /*isDirectInit=*/false, E);
+ if (!HandleInitializedEntity(SubEntity, SubKind, E))
+ return;
+ }
+ // ...and value-initialized for each k < i <= n;
+ if (ArrayLength > Args.size()) {
+ InitializedEntity SubEntity = InitializedEntity::InitializeElement(
+ S.getASTContext(), Args.size(), Entity);
+ InitializationKind SubKind = InitializationKind::CreateValue(
+ Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true);
+ if (!HandleInitializedEntity(SubEntity, SubKind, nullptr, &ArrayFiller))
return;
+ }
+ if (ResultType.isNull()) {
ResultType = S.Context.getConstantArrayType(
AT->getElementType(), llvm::APInt(/*numBits=*/32, ArrayLength),
- nullptr, ArrayType::Normal, 0);
+ /*SizeExpr=*/nullptr, ArrayType::Normal, 0);
}
} else if (auto *RT = Entity.getType()->getAs<RecordType>()) {
+ bool IsUnion = RT->isUnionType();
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 (!IsUnion) {
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ InitializedEntity SubEntity = InitializedEntity::InitializeBase(
+ S.getASTContext(), &Base, false, &Entity);
+ if (EntityIndexToProcess < Args.size()) {
+ // C++ [dcl.init]p16.6.2.2.
+ // ...the object is initialized is follows. Let e1, ..., en be the
+ // elements of the aggregate([dcl.init.aggr]). Let x1, ..., xk be
+ // the elements of the expression-list...The element ei is
+ // copy-initialized with xi for 1 <= i <= k.
+ Expr *E = Args[EntityIndexToProcess];
+ InitializationKind SubKind = InitializationKind::CreateForInit(
+ E->getExprLoc(), /*isDirectInit=*/false, E);
+ if (!HandleInitializedEntity(SubEntity, SubKind, E))
+ return;
+ } else {
+ // We've processed all of the args, but there are still base classes
+ // that have to be initialized.
+ // C++ [dcl.init]p17.6.2.2
+ // The remaining elements...otherwise are value initialzed
+ InitializationKind SubKind = InitializationKind::CreateValue(
+ Kind.getLocation(), Kind.getLocation(), Kind.getLocation(),
+ /*IsImplicit=*/true);
+ if (!HandleInitializedEntity(SubEntity, SubKind, nullptr))
+ return;
+ }
+ EntityIndexToProcess++;
+ }
+ }
- if (!ProcessEntities(BaseRange))
- return;
+ for (FieldDecl *FD : RD->fields()) {
+ // Unnamed bitfields should not be initialized at all, either with an arg
+ // or by default.
+ if (FD->isUnnamedBitfield())
+ continue;
- if (!ProcessEntities(FieldRange))
- return;
+ InitializedEntity SubEntity =
+ InitializedEntity::InitializeMemberFromParenAggInit(FD);
+
+ if (EntityIndexToProcess < Args.size()) {
+ // ...The element ei is copy-initialized with xi for 1 <= i <= k.
+ Expr *E = Args[EntityIndexToProcess];
+
+ // Incomplete array types indicate flexible array members. Do not allow
+ // paren list initializations of structs with these members, as GCC
+ // doesn't either.
+ 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;
+ }
+ InitializationKind SubKind = InitializationKind::CreateForInit(
+ E->getExprLoc(), /*isDirectInit=*/false, E);
+ if (!HandleInitializedEntity(SubEntity, SubKind, E))
+ return;
+
+ // Unions should have only one initializer expression, so we bail out
+ // after processing the first field. If there are more initializers then
+ // it will be caught when we later check whether EntityIndexToProcess is
+ // less than Args.size();
+ if (IsUnion) {
+ InitializedFieldInUnion = FD;
+ EntityIndexToProcess = 1;
+ break;
+ }
+ } else {
+ // We've processed all of the args, but there are still members that
+ // have to be initialized.
+ if (FD->hasInClassInitializer()) {
+ if (!VerifyOnly) {
+ // C++ [dcl.init]p16.6.2.2
+ // The remaining elements are initialized with their default
+ // member initializers, if any
+ ExprResult DIE = S.BuildCXXDefaultInitExpr(
+ Kind.getParenOrBraceRange().getEnd(), FD);
+ if (DIE.isInvalid())
+ return;
+ S.checkInitializerLifetime(SubEntity, DIE.get());
+ InitExprs.push_back(DIE.get());
+ }
+ } else {
+ // C++ [dcl.init]p17.6.2.2
+ // The remaining elements...otherwise are value initialzed
+ if (FD->getType()->isReferenceType()) {
+ Sequence.SetFailed(
+ InitializationSequence::FK_ParenthesizedListInitFailed);
+ if (!VerifyOnly) {
+ SourceRange SR = Kind.getParenOrBraceRange();
+ S.Diag(SR.getEnd(), diag::err_init_reference_member_uninitialized)
+ << FD->getType() << SR;
+ S.Diag(FD->getLocation(), diag::note_uninit_reference_member);
+ }
+ return;
+ }
+ InitializationKind SubKind = InitializationKind::CreateValue(
+ Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true);
+ if (!HandleInitializedEntity(SubEntity, SubKind, nullptr))
+ return;
+ }
+ }
+ EntityIndexToProcess++;
+ }
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()) {
+ // than were required to initialize the element.
+ if (EntityIndexToProcess < Args.size()) {
Sequence.SetFailed(InitializationSequence::FK_ParenthesizedListInitFailed);
if (!VerifyOnly) {
QualType T = Entity.getType();
int InitKind = T->isArrayType() ? 0 : T->isUnionType() ? 3 : 4;
- SourceRange ExcessInitSR(Args[ArgIndexToProcess]->getBeginLoc(),
+ SourceRange ExcessInitSR(Args[EntityIndexToProcess]->getBeginLoc(),
Args.back()->getEndLoc());
S.Diag(Kind.getLocation(), diag::err_excess_initializers)
<< InitKind << ExcessInitSR;
@@ -6152,6 +6341,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
// We're at the end of the line for C: it's either a write-back conversion
// or it's a C assignment. There's no need to check anything else.
if (!S.getLangOpts().CPlusPlus) {
+ assert(Initializer && "Initializer must be non-null");
// If allowed, check whether this is an Objective-C writeback conversion.
if (allowObjCWritebackConversion &&
tryObjCWritebackConversion(S, *this, Entity, Initializer)) {
@@ -6178,7 +6368,8 @@ 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)))) {
+ (Initializer && S.IsDerivedFrom(Initializer->getBeginLoc(),
+ SourceType, DestType))))) {
TryConstructorInitialization(S, Entity, Kind, Args, DestType, DestType,
*this);
@@ -6222,6 +6413,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
// 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).
+ assert(Initializer && "Initializer must be non-null");
TryUserDefinedConversion(S, DestType, Kind, Initializer, *this,
TopLevelOfInitList);
}
@@ -6273,6 +6465,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
// - Otherwise, if the source type is a (possibly cv-qualified) class
// type, conversion functions are considered.
if (!SourceType.isNull() && SourceType->isRecordType()) {
+ assert(Initializer && "Initializer must be non-null");
// For a conversion to _Atomic(T) from either T or a class type derived
// from T, initialize the T object then convert to _Atomic type.
bool NeedAtomicConversion = false;
@@ -6409,6 +6602,7 @@ getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) {
return Sema::AA_Converting;
case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_ParenAggInitMember:
case InitializedEntity::EK_Binding:
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_VectorElement:
@@ -6429,6 +6623,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_ParenAggInitMember:
case InitializedEntity::EK_Result:
case InitializedEntity::EK_StmtExprResult:
case InitializedEntity::EK_New:
@@ -6473,6 +6668,7 @@ static bool shouldDestroyEntity(const InitializedEntity &Entity) {
return false;
case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_ParenAggInitMember:
case InitializedEntity::EK_Binding:
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Parameter:
@@ -6509,6 +6705,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_ParenAggInitMember:
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_TemplateParameter:
@@ -6856,7 +7053,7 @@ PerformConstructorInitialization(Sema &S,
if (isExplicitTemporary(Entity, Kind, NumArgs)) {
// An explicitly-constructed temporary, e.g., X(1, 2).
- if (S.DiagnoseUseOfDecl(Constructor, Loc))
+ if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc))
return ExprError();
TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
@@ -6871,8 +7068,6 @@ PerformConstructorInitialization(Sema &S,
if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(
Step.Function.FoundDecl.getDecl())) {
CalleeDecl = S.findInheritingConstructor(Loc, Constructor, Shadow);
- if (S.DiagnoseUseOfDecl(CalleeDecl, Loc))
- return ExprError();
}
S.MarkFunctionReferenced(Loc, CalleeDecl);
@@ -7077,7 +7272,15 @@ static LifetimeResult getEntityLifetime(
case InitializedEntity::EK_Exception:
// FIXME: Can we diagnose lifetime problems with exceptions?
return {nullptr, LK_FullExpression};
+
+ case InitializedEntity::EK_ParenAggInitMember:
+ // -- A temporary object bound to a reference element of an aggregate of
+ // class type initialized from a parenthesized expression-list
+ // [dcl.init, 9.3] persists until the completion of the full-expression
+ // containing the expression-list.
+ return {nullptr, LK_FullExpression};
}
+
llvm_unreachable("unknown entity kind");
}
@@ -8088,7 +8291,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
case IndirectLocalPathEntry::DefaultInit: {
auto *FD = cast<FieldDecl>(Elem.D);
- Diag(FD->getLocation(), diag::note_init_with_default_member_initalizer)
+ Diag(FD->getLocation(), diag::note_init_with_default_member_initializer)
<< FD << nextPathEntryRange(Path, I + 1, L);
break;
}
@@ -8406,6 +8609,15 @@ ExprResult InitializationSequence::Perform(Sema &S,
<< Init->getSourceRange();
}
+ if (S.getLangOpts().MicrosoftExt && Args.size() == 1 &&
+ isa<PredefinedExpr>(Args[0]) && Entity.getType()->isArrayType()) {
+ // Produce a Microsoft compatibility warning when initializing from a
+ // predefined expression since MSVC treats predefined expressions as string
+ // literals.
+ Expr *Init = Args[0];
+ S.Diag(Init->getBeginLoc(), diag::ext_init_from_predefined) << Init;
+ }
+
// OpenCL v2.0 s6.13.11.1. atomic variables can be initialized in global scope
QualType ETy = Entity.getType();
bool HasGlobalAS = ETy.hasAddressSpace() &&
@@ -9180,30 +9392,34 @@ ExprResult InitializationSequence::Perform(Sema &S,
/*VerifyOnly=*/false, &CurInit);
if (CurInit.get() && ResultType)
*ResultType = CurInit.get()->getType();
+ if (shouldBindAsTemporary(Entity))
+ CurInit = S.MaybeBindToTemporary(CurInit.get());
break;
}
}
}
+ Expr *Init = CurInit.get();
+ if (!Init)
+ return ExprError();
+
// Check whether the initializer has a shorter lifetime than the initialized
// entity, and if not, either lifetime-extend or warn as appropriate.
- if (auto *Init = CurInit.get())
- S.checkInitializerLifetime(Entity, Init);
+ S.checkInitializerLifetime(Entity, Init);
// Diagnose non-fatal problems with the completed initialization.
- if (Entity.getKind() == InitializedEntity::EK_Member &&
+ if (InitializedEntity::EntityKind EK = Entity.getKind();
+ (EK == InitializedEntity::EK_Member ||
+ EK == InitializedEntity::EK_ParenAggInitMember) &&
cast<FieldDecl>(Entity.getDecl())->isBitField())
S.CheckBitFieldInitialization(Kind.getLocation(),
- cast<FieldDecl>(Entity.getDecl()),
- CurInit.get());
+ cast<FieldDecl>(Entity.getDecl()), Init);
// Check for std::move on construction.
- if (const Expr *E = CurInit.get()) {
- CheckMoveOnConstruction(S, E,
- Entity.getKind() == InitializedEntity::EK_Result);
- }
+ CheckMoveOnConstruction(S, Init,
+ Entity.getKind() == InitializedEntity::EK_Result);
- return CurInit;
+ return Init;
}
/// Somewhere within T there is an uninitialized reference subobject.
@@ -9645,7 +9861,8 @@ bool InitializationSequence::Diagnose(Sema &S,
case OR_No_Viable_Function:
if (Kind.getKind() == InitializationKind::IK_Default &&
(Entity.getKind() == InitializedEntity::EK_Base ||
- Entity.getKind() == InitializedEntity::EK_Member) &&
+ Entity.getKind() == InitializedEntity::EK_Member ||
+ Entity.getKind() == InitializedEntity::EK_ParenAggInitMember) &&
isa<CXXConstructorDecl>(S.CurContext)) {
// This is implicit default initialization of a member or
// base within a constructor. If no viable function was
@@ -9788,6 +10005,12 @@ bool InitializationSequence::Diagnose(Sema &S,
TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
/*VerifyOnly=*/false);
break;
+
+ case FK_DesignatedInitForNonAggregate:
+ InitListExpr *InitList = cast<InitListExpr>(Args[0]);
+ S.Diag(Kind.getLocation(), diag::err_designated_init_for_non_aggregate)
+ << Entity.getType() << InitList->getSourceRange();
+ break;
}
PrintInitLocationNote(S, Entity);
@@ -9958,6 +10181,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case FK_ParenthesizedListInitFailed:
OS << "parenthesized list initialization failed";
break;
+
+ case FK_DesignatedInitForNonAggregate:
+ OS << "designated initializer for non-aggregate type";
+ break;
}
OS << '\n';
return;
@@ -10330,7 +10557,7 @@ static bool isOrIsDerivedFromSpecializationOf(CXXRecordDecl *RD,
QualType Sema::DeduceTemplateSpecializationFromInitializer(
TypeSourceInfo *TSInfo, const InitializedEntity &Entity,
- const InitializationKind &Kind, MultiExprArg Inits) {
+ const InitializationKind &Kind, MultiExprArg Inits, ParenListExpr *PL) {
auto *DeducedTST = dyn_cast<DeducedTemplateSpecializationType>(
TSInfo->getType()->getContainedDeducedType());
assert(DeducedTST && "not a deduced template specialization type");
@@ -10400,13 +10627,137 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
- bool HasAnyDeductionGuide = false;
bool AllowExplicit = !Kind.isCopyInit() || ListInit;
- auto tryToResolveOverload =
+ // Return true is the candidate is added successfully, false otherwise.
+ auto addDeductionCandidate = [&](FunctionTemplateDecl *TD,
+ CXXDeductionGuideDecl *GD,
+ DeclAccessPair FoundDecl,
+ bool OnlyListConstructors,
+ bool AllowAggregateDeductionCandidate) {
+ // C++ [over.match.ctor]p1: (non-list copy-initialization from non-class)
+ // For copy-initialization, the candidate functions are all the
+ // converting constructors (12.3.1) of that class.
+ // C++ [over.match.copy]p1: (non-list copy-initialization from class)
+ // The converting constructors of T are candidate functions.
+ if (!AllowExplicit) {
+ // Overload resolution checks whether the deduction guide is declared
+ // explicit for us.
+
+ // When looking for a converting constructor, deduction guides that
+ // could never be called with one argument are not interesting to
+ // check or note.
+ if (GD->getMinRequiredArguments() > 1 ||
+ (GD->getNumParams() == 0 && !GD->isVariadic()))
+ return;
+ }
+
+ // C++ [over.match.list]p1.1: (first phase list initialization)
+ // Initially, the candidate functions are the initializer-list
+ // constructors of the class T
+ if (OnlyListConstructors && !isInitListConstructor(GD))
+ return;
+
+ if (!AllowAggregateDeductionCandidate &&
+ GD->getDeductionCandidateKind() == DeductionCandidate::Aggregate)
+ return;
+
+ // C++ [over.match.list]p1.2: (second phase list initialization)
+ // the candidate functions are all the constructors of the class T
+ // C++ [over.match.ctor]p1: (all other cases)
+ // the candidate functions are all the constructors of the class of
+ // the object being initialized
+
+ // C++ [over.best.ics]p4:
+ // When [...] the constructor [...] is a candidate by
+ // - [over.match.copy] (in all cases)
+ // FIXME: The "second phase of [over.match.list] case can also
+ // theoretically happen here, but it's not clear whether we can
+ // ever have a parameter of the right type.
+ bool SuppressUserConversions = Kind.isCopyInit();
+
+ if (TD) {
+ SmallVector<Expr *, 8> TmpInits;
+ for (Expr *E : Inits)
+ if (auto *DI = dyn_cast<DesignatedInitExpr>(E))
+ TmpInits.push_back(DI->getInit());
+ else
+ TmpInits.push_back(E);
+ AddTemplateOverloadCandidate(
+ TD, FoundDecl, /*ExplicitArgs=*/nullptr, TmpInits, Candidates,
+ SuppressUserConversions,
+ /*PartialOverloading=*/false, AllowExplicit, ADLCallKind::NotADL,
+ /*PO=*/{}, AllowAggregateDeductionCandidate);
+ } else {
+ AddOverloadCandidate(GD, FoundDecl, Inits, Candidates,
+ SuppressUserConversions,
+ /*PartialOverloading=*/false, AllowExplicit);
+ }
+ };
+
+ bool FoundDeductionGuide = false;
+
+ auto TryToResolveOverload =
[&](bool OnlyListConstructors) -> OverloadingResult {
Candidates.clear(OverloadCandidateSet::CSK_Normal);
- HasAnyDeductionGuide = false;
+ bool HasAnyDeductionGuide = false;
+
+ auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) {
+ auto *RD = cast<CXXRecordDecl>(Template->getTemplatedDecl());
+ if (!(RD->getDefinition() && RD->isAggregate()))
+ return;
+ QualType Ty = Context.getRecordType(RD);
+ SmallVector<QualType, 8> ElementTypes;
+
+ InitListChecker CheckInitList(*this, Entity, ListInit, Ty, ElementTypes);
+ if (!CheckInitList.HadError()) {
+ // C++ [over.match.class.deduct]p1.8:
+ // if e_i is of array type and x_i is a braced-init-list, T_i is an
+ // rvalue reference to the declared type of e_i and
+ // C++ [over.match.class.deduct]p1.9:
+ // if e_i is of array type and x_i is a bstring-literal, T_i is an
+ // lvalue reference to the const-qualified declared type of e_i and
+ // C++ [over.match.class.deduct]p1.10:
+ // otherwise, T_i is the declared type of e_i
+ for (int I = 0, E = ListInit->getNumInits();
+ I < E && !isa<PackExpansionType>(ElementTypes[I]); ++I)
+ if (ElementTypes[I]->isArrayType()) {
+ if (isa<InitListExpr>(ListInit->getInit(I)))
+ ElementTypes[I] = Context.getRValueReferenceType(ElementTypes[I]);
+ else if (isa<StringLiteral>(
+ ListInit->getInit(I)->IgnoreParenImpCasts()))
+ ElementTypes[I] =
+ Context.getLValueReferenceType(ElementTypes[I].withConst());
+ }
+
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(Template);
+ for (auto &T : ElementTypes)
+ T.getCanonicalType().Profile(ID);
+ unsigned Hash = ID.ComputeHash();
+ if (AggregateDeductionCandidates.count(Hash) == 0) {
+ if (FunctionTemplateDecl *TD =
+ DeclareImplicitDeductionGuideFromInitList(
+ Template, ElementTypes,
+ TSInfo->getTypeLoc().getEndLoc())) {
+ auto *GD = cast<CXXDeductionGuideDecl>(TD->getTemplatedDecl());
+ GD->setDeductionCandidateKind(DeductionCandidate::Aggregate);
+ AggregateDeductionCandidates[Hash] = GD;
+ addDeductionCandidate(TD, GD, DeclAccessPair::make(TD, AS_public),
+ OnlyListConstructors,
+ /*AllowAggregateDeductionCandidate=*/true);
+ }
+ } else {
+ CXXDeductionGuideDecl *GD = AggregateDeductionCandidates[Hash];
+ FunctionTemplateDecl *TD = GD->getDescribedFunctionTemplate();
+ assert(TD && "aggregate deduction candidate is function template");
+ addDeductionCandidate(TD, GD, DeclAccessPair::make(TD, AS_public),
+ OnlyListConstructors,
+ /*AllowAggregateDeductionCandidate=*/true);
+ }
+ HasAnyDeductionGuide = true;
+ }
+ };
for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
@@ -10414,7 +10765,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
continue;
auto *TD = dyn_cast<FunctionTemplateDecl>(D);
- auto *GD = dyn_cast_or_null<CXXDeductionGuideDecl>(
+ auto *GD = dyn_cast_if_present<CXXDeductionGuideDecl>(
TD ? TD->getTemplatedDecl() : dyn_cast<FunctionDecl>(D));
if (!GD)
continue;
@@ -10422,53 +10773,30 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
if (!GD->isImplicit())
HasAnyDeductionGuide = true;
- // C++ [over.match.ctor]p1: (non-list copy-initialization from non-class)
- // For copy-initialization, the candidate functions are all the
- // converting constructors (12.3.1) of that class.
- // C++ [over.match.copy]p1: (non-list copy-initialization from class)
- // The converting constructors of T are candidate functions.
- if (!AllowExplicit) {
- // Overload resolution checks whether the deduction guide is declared
- // explicit for us.
-
- // When looking for a converting constructor, deduction guides that
- // could never be called with one argument are not interesting to
- // check or note.
- if (GD->getMinRequiredArguments() > 1 ||
- (GD->getNumParams() == 0 && !GD->isVariadic()))
- continue;
+ addDeductionCandidate(TD, GD, I.getPair(), OnlyListConstructors,
+ /*AllowAggregateDeductionCandidate=*/false);
+ }
+
+ // C++ [over.match.class.deduct]p1.4:
+ // if C is defined and its definition satisfies the conditions for an
+ // aggregate class ([dcl.init.aggr]) with the assumption that any
+ // dependent base class has no virtual functions and no virtual base
+ // classes, and the initializer is a non-empty braced-init-list or
+ // parenthesized expression-list, and there are no deduction-guides for
+ // C, the set contains an additional function template, called the
+ // aggregate deduction candidate, defined as follows.
+ if (getLangOpts().CPlusPlus20 && !HasAnyDeductionGuide) {
+ if (ListInit && ListInit->getNumInits()) {
+ SynthesizeAggrGuide(ListInit);
+ } else if (PL && PL->getNumExprs()) {
+ InitListExpr TempListInit(getASTContext(), PL->getLParenLoc(),
+ PL->exprs(), PL->getRParenLoc());
+ SynthesizeAggrGuide(&TempListInit);
}
+ }
- // C++ [over.match.list]p1.1: (first phase list initialization)
- // Initially, the candidate functions are the initializer-list
- // constructors of the class T
- if (OnlyListConstructors && !isInitListConstructor(GD))
- continue;
+ FoundDeductionGuide = FoundDeductionGuide || HasAnyDeductionGuide;
- // C++ [over.match.list]p1.2: (second phase list initialization)
- // the candidate functions are all the constructors of the class T
- // C++ [over.match.ctor]p1: (all other cases)
- // the candidate functions are all the constructors of the class of
- // the object being initialized
-
- // C++ [over.best.ics]p4:
- // When [...] the constructor [...] is a candidate by
- // - [over.match.copy] (in all cases)
- // FIXME: The "second phase of [over.match.list] case can also
- // theoretically happen here, but it's not clear whether we can
- // ever have a parameter of the right type.
- bool SuppressUserConversions = Kind.isCopyInit();
-
- if (TD)
- AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr,
- Inits, Candidates, SuppressUserConversions,
- /*PartialOverloading*/ false,
- AllowExplicit);
- else
- AddOverloadCandidate(GD, I.getPair(), Inits, Candidates,
- SuppressUserConversions,
- /*PartialOverloading*/ false, AllowExplicit);
- }
return Candidates.BestViableFunction(*this, Kind.getLocation(), Best);
};
@@ -10504,7 +10832,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
}
if (TryListConstructors)
- Result = tryToResolveOverload(/*OnlyListConstructor*/true);
+ Result = TryToResolveOverload(/*OnlyListConstructor*/true);
// Then unwrap the initializer list and try again considering all
// constructors.
Inits = MultiExprArg(ListInit->getInits(), ListInit->getNumInits());
@@ -10513,7 +10841,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// If list-initialization fails, or if we're doing any other kind of
// initialization, we (eventually) consider constructors.
if (Result == OR_No_Viable_Function)
- Result = tryToResolveOverload(/*OnlyListConstructor*/false);
+ Result = TryToResolveOverload(/*OnlyListConstructor*/false);
switch (Result) {
case OR_Ambiguous:
@@ -10567,7 +10895,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// Make sure we didn't select an unusable deduction guide, and mark it
// as referenced.
- DiagnoseUseOfDecl(Best->Function, Kind.getLocation());
+ DiagnoseUseOfDecl(Best->FoundDecl, Kind.getLocation());
MarkFunctionReferenced(Kind.getLocation(), Best->Function);
break;
}
@@ -10583,7 +10911,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// Warn if CTAD was used on a type that does not have any user-defined
// deduction guides.
- if (!HasAnyDeductionGuide) {
+ if (!FoundDeductionGuide) {
Diag(TSInfo->getTypeLoc().getBeginLoc(),
diag::warn_ctad_maybe_unsupported)
<< TemplateName;