aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaInit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaInit.cpp')
-rw-r--r--lib/Sema/SemaInit.cpp1210
1 files changed, 792 insertions, 418 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index bc1069609336..10cb7acad567 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Initialization.h"
@@ -197,7 +198,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
llvm::APInt ConstVal(32, StrLength);
// Return a new array type (C99 6.7.8p22).
DeclT = S.Context.getConstantArrayType(IAT->getElementType(),
- ConstVal,
+ ConstVal, nullptr,
ArrayType::Normal, 0);
updateStringLiteralType(Str, DeclT);
return;
@@ -271,13 +272,24 @@ namespace {
/// point. CheckDesignatedInitializer() recursively steps into the
/// designated subobject and manages backing out the recursion to
/// initialize the subobjects after the one designated.
+///
+/// If an initializer list contains any designators, we build a placeholder
+/// structured list even in 'verify only' mode, so that we can track which
+/// elements need 'empty' initializtion.
class InitListChecker {
Sema &SemaRef;
- bool hadError;
- bool VerifyOnly; // no diagnostics, no structure building
+ bool hadError = false;
+ bool VerifyOnly; // No diagnostics.
bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode.
- llvm::DenseMap<InitListExpr *, InitListExpr *> SyntacticToSemantic;
- InitListExpr *FullyStructuredList;
+ bool InOverloadResolution;
+ InitListExpr *FullyStructuredList = nullptr;
+ NoInitExpr *DummyExpr = nullptr;
+
+ NoInitExpr *getDummyInit() {
+ if (!DummyExpr)
+ DummyExpr = new (SemaRef.Context) NoInitExpr(SemaRef.Context.VoidTy);
+ return DummyExpr;
+ }
void CheckImplicitInitList(const InitializedEntity &Entity,
InitListExpr *ParentIList, QualType T,
@@ -352,14 +364,71 @@ class InitListChecker {
void UpdateStructuredListElement(InitListExpr *StructuredList,
unsigned &StructuredIndex,
Expr *expr);
+ InitListExpr *createInitListExpr(QualType CurrentObjectType,
+ SourceRange InitRange,
+ unsigned ExpectedNumInits);
int numArrayElements(QualType DeclType);
int numStructUnionElements(QualType DeclType);
- static ExprResult PerformEmptyInit(Sema &SemaRef,
- SourceLocation Loc,
- const InitializedEntity &Entity,
- bool VerifyOnly,
- bool TreatUnavailableAsInvalid);
+ 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 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;
+
+ if (InOverloadResolution && SemaRef.getLangOpts().CPlusPlus) {
+ // In overload resolution, we have to strictly enforce the rules, and so
+ // don't allow any overriding of prior initializers. This matters for a
+ // case such as:
+ //
+ // union U { int a, b; };
+ // struct S { int a, b; };
+ // void f(U), f(S);
+ //
+ // Here, f({.a = 1, .b = 2}) is required to call the struct overload. For
+ // consistency, we disallow all overriding of prior initializers in
+ // overload resolution, not only overriding of union members.
+ hadError = true;
+ } else if (OldInit->getType().isDestructedType() && !FullyOverwritten) {
+ // If we'll be keeping around the old initializer but overwriting part of
+ // the object it initialized, and that object is not trivially
+ // destructible, this can leak. Don't allow that, not even as an
+ // extension.
+ //
+ // FIXME: It might be reasonable to allow this in cases where the part of
+ // the initializer that we're overriding has trivial destruction.
+ DiagID = diag::err_initializer_overrides_destructed;
+ } else if (!OldInit->getSourceRange().isValid()) {
+ // We need to check on source range validity because the previous
+ // initializer does not have to be an explicit initializer. e.g.,
+ //
+ // struct P { int a, b; };
+ // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
+ //
+ // There is an overwrite taking place because the first braced initializer
+ // list "{ .a = 2 }" already provides value for .p.b (which is zero).
+ //
+ // Such overwrites are harmless, so we don't diagnose them. (Note that in
+ // C++, this cannot be reached unless we've already seen and diagnosed a
+ // different conformance issue, such as a mixture of designated and
+ // non-designated initializers or a multi-level designator.)
+ return;
+ }
+
+ if (!VerifyOnly) {
+ SemaRef.Diag(NewInitRange.getBegin(), DiagID)
+ << NewInitRange << FullyOverwritten << OldInit->getType();
+ SemaRef.Diag(OldInit->getBeginLoc(), diag::note_previous_initializer)
+ << (OldInit->HasSideEffects(SemaRef.Context) && FullyOverwritten)
+ << OldInit->getSourceRange();
+ }
+ }
// Explanation on the "FillWithNoInit" mode:
//
@@ -399,9 +468,9 @@ class InitListChecker {
SourceLocation Loc);
public:
- InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T, bool VerifyOnly,
- bool TreatUnavailableAsInvalid);
+ InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL,
+ QualType &T, bool VerifyOnly, bool TreatUnavailableAsInvalid,
+ bool InOverloadResolution = false);
bool HadError() { return hadError; }
// Retrieves the fully-structured initializer list used for
@@ -411,11 +480,8 @@ public:
} // end anonymous namespace
-ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
- SourceLocation Loc,
- const InitializedEntity &Entity,
- bool VerifyOnly,
- bool TreatUnavailableAsInvalid) {
+ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc,
+ const InitializedEntity &Entity) {
InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
true);
MultiExprArg SubInit;
@@ -517,43 +583,44 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
<< Entity.getElementIndex();
}
}
+ hadError = true;
return ExprError();
}
- return VerifyOnly ? ExprResult(static_cast<Expr *>(nullptr))
+ return VerifyOnly ? ExprResult()
: InitSeq.Perform(SemaRef, Entity, Kind, SubInit);
}
void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity,
SourceLocation Loc) {
- assert(VerifyOnly &&
- "CheckEmptyInitializable is only inteded for verification mode.");
- if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true,
- TreatUnavailableAsInvalid).isInvalid())
- hadError = true;
+ // If we're building a fully-structured list, we'll check this at the end
+ // once we know which elements are actually initialized. Otherwise, we know
+ // that there are no designators so we can just check now.
+ if (FullyStructuredList)
+ return;
+ PerformEmptyInit(Loc, Entity);
}
void InitListChecker::FillInEmptyInitForBase(
unsigned Init, const CXXBaseSpecifier &Base,
const InitializedEntity &ParentEntity, InitListExpr *ILE,
bool &RequiresSecondPass, bool FillWithNoInit) {
- assert(Init < ILE->getNumInits() && "should have been expanded");
-
InitializedEntity BaseEntity = InitializedEntity::InitializeBase(
SemaRef.Context, &Base, false, &ParentEntity);
- if (!ILE->getInit(Init)) {
- ExprResult BaseInit =
- FillWithNoInit
- ? new (SemaRef.Context) NoInitExpr(Base.getType())
- : PerformEmptyInit(SemaRef, ILE->getEndLoc(), BaseEntity,
- /*VerifyOnly*/ false, TreatUnavailableAsInvalid);
+ if (Init >= ILE->getNumInits() || !ILE->getInit(Init)) {
+ ExprResult BaseInit = FillWithNoInit
+ ? new (SemaRef.Context) NoInitExpr(Base.getType())
+ : PerformEmptyInit(ILE->getEndLoc(), BaseEntity);
if (BaseInit.isInvalid()) {
hadError = true;
return;
}
- ILE->setInit(Init, BaseInit.getAs<Expr>());
+ if (!VerifyOnly) {
+ assert(Init < ILE->getNumInits() && "should have been expanded");
+ ILE->setInit(Init, BaseInit.getAs<Expr>());
+ }
} else if (InitListExpr *InnerILE =
dyn_cast<InitListExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(BaseEntity, InnerILE, RequiresSecondPass,
@@ -576,12 +643,14 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
InitializedEntity MemberEntity
= InitializedEntity::InitializeMember(Field, &ParentEntity);
- if (const RecordType *RType = ILE->getType()->getAs<RecordType>())
- if (!RType->getDecl()->isUnion())
- assert(Init < NumInits && "This ILE should have been expanded");
-
if (Init >= NumInits || !ILE->getInit(Init)) {
+ if (const RecordType *RType = ILE->getType()->getAs<RecordType>())
+ if (!RType->getDecl()->isUnion())
+ assert((Init < NumInits || VerifyOnly) &&
+ "This ILE should have been expanded");
+
if (FillWithNoInit) {
+ assert(!VerifyOnly && "should not fill with no-init in verify-only mode");
Expr *Filler = new (SemaRef.Context) NoInitExpr(Field->getType());
if (Init < NumInits)
ILE->setInit(Init, Filler);
@@ -594,6 +663,9 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
// members in the aggregate, then each member not explicitly initialized
// shall be initialized from its brace-or-equal-initializer [...]
if (Field->hasInClassInitializer()) {
+ if (VerifyOnly)
+ return;
+
ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
if (DIE.isInvalid()) {
hadError = true;
@@ -610,28 +682,28 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
}
if (Field->getType()->isReferenceType()) {
- // C++ [dcl.init.aggr]p9:
- // If an incomplete or empty initializer-list leaves a
- // member of reference type uninitialized, the program is
- // ill-formed.
- SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
- << Field->getType()
- << ILE->getSyntacticForm()->getSourceRange();
- SemaRef.Diag(Field->getLocation(),
- diag::note_uninit_reference_member);
+ if (!VerifyOnly) {
+ // C++ [dcl.init.aggr]p9:
+ // If an incomplete or empty initializer-list leaves a
+ // member of reference type uninitialized, the program is
+ // ill-formed.
+ SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
+ << Field->getType()
+ << ILE->getSyntacticForm()->getSourceRange();
+ SemaRef.Diag(Field->getLocation(),
+ diag::note_uninit_reference_member);
+ }
hadError = true;
return;
}
- ExprResult MemberInit = PerformEmptyInit(SemaRef, Loc, MemberEntity,
- /*VerifyOnly*/false,
- TreatUnavailableAsInvalid);
+ ExprResult MemberInit = PerformEmptyInit(Loc, MemberEntity);
if (MemberInit.isInvalid()) {
hadError = true;
return;
}
- if (hadError) {
+ if (hadError || VerifyOnly) {
// Do nothing
} else if (Init < NumInits) {
ILE->setInit(Init, MemberInit.getAs<Expr>());
@@ -644,14 +716,15 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
RequiresSecondPass = true;
}
} else if (InitListExpr *InnerILE
- = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ = dyn_cast<InitListExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(MemberEntity, InnerILE,
RequiresSecondPass, ILE, Init, FillWithNoInit);
- else if (DesignatedInitUpdateExpr *InnerDIUE
- = dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init)))
+ } else if (DesignatedInitUpdateExpr *InnerDIUE =
+ dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(MemberEntity, InnerDIUE->getUpdater(),
RequiresSecondPass, ILE, Init,
/*FillWithNoInit =*/true);
+ }
}
/// Recursively replaces NULL values within the given initializer list
@@ -667,6 +740,11 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
+ // We don't need to do any checks when just filling NoInitExprs; that can't
+ // fail.
+ if (FillWithNoInit && VerifyOnly)
+ return;
+
// If this is a nested initializer list, we might have changed its contents
// (and therefore some of its properties, such as instantiation-dependence)
// while filling it in. Inform the outer initializer list so that its state
@@ -709,7 +787,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
unsigned NumElems = numStructUnionElements(ILE->getType());
if (RDecl->hasFlexibleArrayMember())
++NumElems;
- if (ILE->getNumInits() < NumElems)
+ if (!VerifyOnly && ILE->getNumInits() < NumElems)
ILE->resizeInits(SemaRef.Context, NumElems);
unsigned Init = 0;
@@ -771,6 +849,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
} else
ElementType = ILE->getType();
+ bool SkipEmptyInitChecks = false;
for (unsigned Init = 0; Init != NumElements; ++Init) {
if (hadError)
return;
@@ -779,21 +858,25 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
ElementEntity.getKind() == InitializedEntity::EK_VectorElement)
ElementEntity.setElementIndex(Init);
- if (Init >= NumInits && ILE->hasArrayFiller())
+ if (Init >= NumInits && (ILE->hasArrayFiller() || SkipEmptyInitChecks))
return;
Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr);
if (!InitExpr && Init < NumInits && ILE->hasArrayFiller())
ILE->setInit(Init, ILE->getArrayFiller());
else if (!InitExpr && !ILE->hasArrayFiller()) {
+ // In VerifyOnly mode, there's no point performing empty initialization
+ // more than once.
+ if (SkipEmptyInitChecks)
+ continue;
+
Expr *Filler = nullptr;
if (FillWithNoInit)
Filler = new (SemaRef.Context) NoInitExpr(ElementType);
else {
ExprResult ElementInit =
- PerformEmptyInit(SemaRef, ILE->getEndLoc(), ElementEntity,
- /*VerifyOnly*/ false, TreatUnavailableAsInvalid);
+ PerformEmptyInit(ILE->getEndLoc(), ElementEntity);
if (ElementInit.isInvalid()) {
hadError = true;
return;
@@ -804,6 +887,8 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
if (hadError) {
// Do nothing
+ } else if (VerifyOnly) {
+ SkipEmptyInitChecks = true;
} else if (Init < NumInits) {
// For arrays, just set the expression used for value-initialization
// of the "holes" in the array.
@@ -829,34 +914,46 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
}
}
} else if (InitListExpr *InnerILE
- = dyn_cast_or_null<InitListExpr>(InitExpr))
+ = dyn_cast_or_null<InitListExpr>(InitExpr)) {
FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass,
ILE, Init, FillWithNoInit);
- else if (DesignatedInitUpdateExpr *InnerDIUE
- = dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr))
+ } else if (DesignatedInitUpdateExpr *InnerDIUE =
+ dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr)) {
FillInEmptyInitializations(ElementEntity, InnerDIUE->getUpdater(),
RequiresSecondPass, ILE, Init,
/*FillWithNoInit =*/true);
+ }
}
}
+static bool hasAnyDesignatedInits(const InitListExpr *IL) {
+ for (const Stmt *Init : *IL)
+ if (Init && isa<DesignatedInitExpr>(Init))
+ return true;
+ return false;
+}
+
InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T,
- bool VerifyOnly,
- bool TreatUnavailableAsInvalid)
- : SemaRef(S), VerifyOnly(VerifyOnly),
- TreatUnavailableAsInvalid(TreatUnavailableAsInvalid) {
- // FIXME: Check that IL isn't already the semantic form of some other
- // InitListExpr. If it is, we'd create a broken AST.
-
- hadError = false;
-
- FullyStructuredList =
- getStructuredSubobjectInit(IL, 0, T, nullptr, 0, IL->getSourceRange());
+ InitListExpr *IL, QualType &T, bool VerifyOnly,
+ bool TreatUnavailableAsInvalid,
+ bool InOverloadResolution)
+ : SemaRef(S), VerifyOnly(VerifyOnly),
+ TreatUnavailableAsInvalid(TreatUnavailableAsInvalid),
+ InOverloadResolution(InOverloadResolution) {
+ if (!VerifyOnly || hasAnyDesignatedInits(IL)) {
+ FullyStructuredList =
+ createInitListExpr(T, IL->getSourceRange(), IL->getNumInits());
+
+ // FIXME: Check that IL isn't already the semantic form of some other
+ // InitListExpr. If it is, we'd create a broken AST.
+ if (!VerifyOnly)
+ FullyStructuredList->setSyntacticForm(IL);
+ }
+
CheckExplicitInitList(Entity, IL, T, FullyStructuredList,
/*TopLevelObject=*/true);
- if (!hadError && !VerifyOnly) {
+ if (!hadError && FullyStructuredList) {
bool RequiresSecondPass = false;
FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass,
/*OuterILE=*/nullptr, /*OuterIndex=*/0);
@@ -877,7 +974,7 @@ int InitListChecker::numArrayElements(QualType DeclType) {
}
int InitListChecker::numStructUnionElements(QualType DeclType) {
- RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl();
int InitializableMembers = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(structDecl))
InitializableMembers += CXXRD->getNumBases();
@@ -936,7 +1033,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
else if (T->isRecordType())
maxElements = numStructUnionElements(T);
else if (T->isVectorType())
- maxElements = T->getAs<VectorType>()->getNumElements();
+ maxElements = T->castAs<VectorType>()->getNumElements();
else
llvm_unreachable("CheckImplicitInitList(): Illegal type");
@@ -963,7 +1060,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
StructuredSubobjectInitList,
StructuredSubobjectInitIndex);
- if (!VerifyOnly) {
+ if (StructuredSubobjectInitList) {
StructuredSubobjectInitList->setType(T);
unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
@@ -977,7 +1074,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
}
// Complain about missing braces.
- if ((T->isArrayType() || T->isRecordType()) &&
+ if (!VerifyOnly && (T->isArrayType() || T->isRecordType()) &&
!ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
!isIdiomaticBraceElisionEntity(Entity)) {
SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(),
@@ -993,7 +1090,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
// Warn if this type won't be an aggregate in future versions of C++.
auto *CXXRD = T->getAsCXXRecordDecl();
- if (CXXRD && CXXRD->hasUserDeclaredConstructor()) {
+ if (!VerifyOnly && CXXRD && CXXRD->hasUserDeclaredConstructor()) {
SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(),
diag::warn_cxx2a_compat_aggregate_init_with_ctors)
<< StructuredSubobjectInitList->getSourceRange() << T;
@@ -1074,67 +1171,46 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
InitListExpr *IList, QualType &T,
InitListExpr *StructuredList,
bool TopLevelObject) {
- if (!VerifyOnly) {
- SyntacticToSemantic[IList] = StructuredList;
- StructuredList->setSyntacticForm(IList);
- }
-
unsigned Index = 0, StructuredIndex = 0;
CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true,
Index, StructuredList, StructuredIndex, TopLevelObject);
- if (!VerifyOnly) {
+ if (StructuredList) {
QualType ExprTy = T;
if (!ExprTy->isArrayType())
ExprTy = ExprTy.getNonLValueExprType(SemaRef.Context);
- IList->setType(ExprTy);
+ if (!VerifyOnly)
+ IList->setType(ExprTy);
StructuredList->setType(ExprTy);
}
if (hadError)
return;
- if (Index < IList->getNumInits()) {
+ // Don't complain for incomplete types, since we'll get an error elsewhere.
+ if (Index < IList->getNumInits() && !T->isIncompleteType()) {
// We have leftover initializers
+ bool ExtraInitsIsError = SemaRef.getLangOpts().CPlusPlus ||
+ (SemaRef.getLangOpts().OpenCL && T->isVectorType());
+ hadError = ExtraInitsIsError;
if (VerifyOnly) {
- if (SemaRef.getLangOpts().CPlusPlus ||
- (SemaRef.getLangOpts().OpenCL &&
- IList->getType()->isVectorType())) {
- hadError = true;
- }
return;
- }
-
- if (StructuredIndex == 1 &&
- IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) ==
- SIF_None) {
- unsigned DK = diag::ext_excess_initializers_in_char_array_initializer;
- if (SemaRef.getLangOpts().CPlusPlus) {
- DK = diag::err_excess_initializers_in_char_array_initializer;
- hadError = true;
- }
- // Special-case
+ } else if (StructuredIndex == 1 &&
+ IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) ==
+ SIF_None) {
+ unsigned DK =
+ ExtraInitsIsError
+ ? diag::err_excess_initializers_in_char_array_initializer
+ : diag::ext_excess_initializers_in_char_array_initializer;
SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
<< IList->getInit(Index)->getSourceRange();
- } else if (!T->isIncompleteType()) {
- // Don't complain for incomplete types, since we'll get an error
- // elsewhere
- QualType CurrentObjectType = StructuredList->getType();
- int initKind =
- CurrentObjectType->isArrayType()? 0 :
- CurrentObjectType->isVectorType()? 1 :
- CurrentObjectType->isScalarType()? 2 :
- CurrentObjectType->isUnionType()? 3 :
- 4;
-
- unsigned DK = diag::ext_excess_initializers;
- if (SemaRef.getLangOpts().CPlusPlus) {
- DK = diag::err_excess_initializers;
- hadError = true;
- }
- if (SemaRef.getLangOpts().OpenCL && initKind == 1) {
- DK = diag::err_excess_initializers;
- hadError = true;
- }
-
+ } else {
+ int initKind = T->isArrayType() ? 0 :
+ T->isVectorType() ? 1 :
+ T->isScalarType() ? 2 :
+ T->isUnionType() ? 3 :
+ 4;
+
+ unsigned DK = ExtraInitsIsError ? diag::err_excess_initializers
+ : diag::ext_excess_initializers;
SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
<< initKind << IList->getInit(Index)->getSourceRange();
}
@@ -1188,7 +1264,7 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
} else if (DeclType->isRecordType()) {
assert(DeclType->isAggregateType() &&
"non-aggregate records should be handed in CheckSubElementType");
- RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
auto Bases =
CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(),
CXXRecordDecl::base_class_iterator());
@@ -1246,42 +1322,22 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
if (SubInitList->getNumInits() == 1 &&
IsStringInit(SubInitList->getInit(0), ElemType, SemaRef.Context) ==
SIF_None) {
+ // FIXME: It would be more faithful and no less correct to include an
+ // InitListExpr in the semantic form of the initializer list in this case.
expr = SubInitList->getInit(0);
- } else if (!SemaRef.getLangOpts().CPlusPlus) {
- InitListExpr *InnerStructuredList
- = getStructuredSubobjectInit(IList, Index, ElemType,
- StructuredList, StructuredIndex,
- SubInitList->getSourceRange(), true);
- CheckExplicitInitList(Entity, SubInitList, ElemType,
- InnerStructuredList);
-
- if (!hadError && !VerifyOnly) {
- bool RequiresSecondPass = false;
- FillInEmptyInitializations(Entity, InnerStructuredList,
- RequiresSecondPass, StructuredList,
- StructuredIndex);
- if (RequiresSecondPass && !hadError)
- FillInEmptyInitializations(Entity, InnerStructuredList,
- RequiresSecondPass, StructuredList,
- StructuredIndex);
- }
- ++StructuredIndex;
- ++Index;
- return;
}
- // C++ initialization is handled later.
+ // Nested aggregate initialization and C++ initialization are handled later.
} else if (isa<ImplicitValueInitExpr>(expr)) {
// This happens during template instantiation when we see an InitListExpr
// that we've already checked once.
assert(SemaRef.Context.hasSameType(expr->getType(), ElemType) &&
"found implicit initialization for the wrong type");
- if (!VerifyOnly)
- UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
return;
}
- if (SemaRef.getLangOpts().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus || isa<InitListExpr>(expr)) {
// C++ [dcl.init.aggr]p2:
// Each member is copy-initialized from the corresponding
// initializer-clause.
@@ -1289,7 +1345,16 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// FIXME: Better EqualLoc?
InitializationKind Kind =
InitializationKind::CreateCopy(expr->getBeginLoc(), SourceLocation());
- InitializationSequence Seq(SemaRef, Entity, Kind, expr,
+
+ // Vector elements can be initialized from other vectors in which case
+ // we need initialization entity with a type of a vector (and not a vector
+ // element!) initializing multiple vector elements.
+ auto TmpEntity =
+ (ElemType->isExtVectorType() && !Entity.getType()->isExtVectorType())
+ ? InitializedEntity::InitializeTemporary(ElemType)
+ : Entity;
+
+ InitializationSequence Seq(SemaRef, TmpEntity, Kind, expr,
/*TopLevelOfInitList*/ true);
// C++14 [dcl.init.aggr]p13:
@@ -1300,15 +1365,18 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// assignment-expression.
if (Seq || isa<InitListExpr>(expr)) {
if (!VerifyOnly) {
- ExprResult Result =
- Seq.Perform(SemaRef, Entity, Kind, expr);
+ ExprResult Result = Seq.Perform(SemaRef, TmpEntity, Kind, expr);
if (Result.isInvalid())
hadError = true;
UpdateStructuredListElement(StructuredList, StructuredIndex,
Result.getAs<Expr>());
- } else if (!Seq)
+ } else if (!Seq) {
hadError = true;
+ } else if (StructuredList) {
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ getDummyInit());
+ }
++Index;
return;
}
@@ -1325,10 +1393,11 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// type here, though.
if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) {
- if (!VerifyOnly) {
+ // FIXME: Should we do this checking in verify-only mode?
+ if (!VerifyOnly)
CheckStringInit(expr, ElemType, arrayType, SemaRef);
+ if (StructuredList)
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
- }
++Index;
return;
}
@@ -1354,8 +1423,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
hadError = true;
else {
ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.get());
- if (ExprRes.isInvalid())
- hadError = true;
+ if (ExprRes.isInvalid())
+ hadError = true;
}
UpdateStructuredListElement(StructuredList, StructuredIndex,
ExprRes.getAs<Expr>());
@@ -1380,10 +1449,15 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
++StructuredIndex;
} else {
if (!VerifyOnly) {
- // We cannot initialize this element, so let
- // PerformCopyInitialization produce the appropriate diagnostic.
- SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr,
- /*TopLevelOfInitList=*/true);
+ // We cannot initialize this element, so let PerformCopyInitialization
+ // produce the appropriate diagnostic. We already checked that this
+ // initialization will fail.
+ ExprResult Copy =
+ SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr,
+ /*TopLevelOfInitList=*/true);
+ (void)Copy;
+ assert(Copy.isInvalid() &&
+ "expected non-aggregate initialization to fail");
}
hadError = true;
++Index;
@@ -1416,7 +1490,7 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity,
<< IList->getSourceRange();
// Initialize the complex number.
- QualType elementType = DeclType->getAs<ComplexType>()->getElementType();
+ QualType elementType = DeclType->castAs<ComplexType>()->getElementType();
InitializedEntity ElementEntity =
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
@@ -1467,17 +1541,18 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
return;
}
+ ExprResult Result;
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity,expr))
- hadError = true;
- ++Index;
- return;
+ if (SemaRef.CanPerformCopyInitialization(Entity, expr))
+ Result = getDummyInit();
+ else
+ Result = ExprError();
+ } else {
+ Result =
+ SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
+ /*TopLevelOfInitList=*/true);
}
- ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
- /*TopLevelOfInitList=*/true);
-
Expr *ResultExpr = nullptr;
if (Result.isInvalid())
@@ -1485,8 +1560,9 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
else {
ResultExpr = Result.getAs<Expr>();
- if (ResultExpr != expr) {
+ if (ResultExpr != expr && !VerifyOnly) {
// The type was promoted, update initializer list.
+ // FIXME: Why are we updating the syntactic init list?
IList->setInit(Index, ResultExpr);
}
}
@@ -1528,22 +1604,25 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
return;
}
+ ExprResult Result;
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity,expr))
- hadError = true;
- ++Index;
- return;
+ if (SemaRef.CanPerformCopyInitialization(Entity,expr))
+ Result = getDummyInit();
+ else
+ Result = ExprError();
+ } else {
+ Result =
+ SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
+ /*TopLevelOfInitList=*/true);
}
- ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
- /*TopLevelOfInitList=*/true);
-
if (Result.isInvalid())
hadError = true;
expr = Result.getAs<Expr>();
- IList->setInit(Index, expr);
+ // FIXME: Why are we updating the syntactic init list?
+ if (!VerifyOnly)
+ IList->setInit(Index, expr);
if (hadError)
++StructuredIndex;
@@ -1557,17 +1636,16 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
- const VectorType *VT = DeclType->getAs<VectorType>();
+ const VectorType *VT = DeclType->castAs<VectorType>();
unsigned maxElements = VT->getNumElements();
unsigned numEltsInit = 0;
QualType elementType = VT->getElementType();
if (Index >= IList->getNumInits()) {
// Make sure the element type can be value-initialized.
- if (VerifyOnly)
- CheckEmptyInitializable(
- InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity),
- IList->getEndLoc());
+ CheckEmptyInitializable(
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity),
+ IList->getEndLoc());
return;
}
@@ -1576,25 +1654,27 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
// instead of breaking it apart (which is doomed to failure anyway).
Expr *Init = IList->getInit(Index);
if (!isa<InitListExpr>(Init) && Init->getType()->isVectorType()) {
+ ExprResult Result;
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity, Init))
- hadError = true;
- ++Index;
- return;
+ if (SemaRef.CanPerformCopyInitialization(Entity, Init))
+ Result = getDummyInit();
+ else
+ Result = ExprError();
+ } else {
+ Result =
+ SemaRef.PerformCopyInitialization(Entity, Init->getBeginLoc(), Init,
+ /*TopLevelOfInitList=*/true);
}
- ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, Init->getBeginLoc(), Init,
- /*TopLevelOfInitList=*/true);
-
Expr *ResultExpr = nullptr;
if (Result.isInvalid())
hadError = true; // types weren't compatible.
else {
ResultExpr = Result.getAs<Expr>();
- if (ResultExpr != Init) {
+ if (ResultExpr != Init && !VerifyOnly) {
// The type was promoted, update initializer list.
+ // FIXME: Why are we updating the syntactic init list?
IList->setInit(Index, ResultExpr);
}
}
@@ -1613,8 +1693,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) {
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits()) {
- if (VerifyOnly)
- CheckEmptyInitializable(ElementEntity, IList->getEndLoc());
+ CheckEmptyInitializable(ElementEntity, IList->getEndLoc());
break;
}
@@ -1627,7 +1706,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
return;
bool isBigEndian = SemaRef.Context.getTargetInfo().isBigEndian();
- const VectorType *T = Entity.getType()->getAs<VectorType>();
+ const VectorType *T = Entity.getType()->castAs<VectorType>();
if (isBigEndian && (T->getVectorKind() == VectorType::NeonVector ||
T->getVectorKind() == VectorType::NeonPolyVector)) {
// The ability to use vector initializer lists is a GNU vector extension
@@ -1683,7 +1762,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
++numEltsInit;
} else {
QualType VecType;
- const VectorType *IVT = IType->getAs<VectorType>();
+ const VectorType *IVT = IType->castAs<VectorType>();
unsigned numIElts = IVT->getNumElements();
if (IType->isExtVectorType())
@@ -1757,8 +1836,10 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
// of the structured initializer list doesn't match exactly,
// because doing so would involve allocating one character
// constant for each string.
- if (!VerifyOnly) {
+ // FIXME: Should we do these checks in verify-only mode too?
+ if (!VerifyOnly)
CheckStringInit(IList->getInit(Index), DeclType, arrayType, SemaRef);
+ if (StructuredList) {
UpdateStructuredListElement(StructuredList, StructuredIndex,
IList->getInit(Index));
StructuredList->resizeInits(SemaRef.Context, StructuredIndex);
@@ -1854,15 +1935,14 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
SemaRef.Diag(IList->getBeginLoc(), diag::ext_typecheck_zero_array_size);
}
- DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements,
- ArrayType::Normal, 0);
+ DeclType = SemaRef.Context.getConstantArrayType(
+ elementType, maxElements, nullptr, ArrayType::Normal, 0);
}
- if (!hadError && VerifyOnly) {
+ if (!hadError) {
// If there are any members of the array that get value-initialized, check
// that is possible. That happens if we know the bound and don't have
// enough elements, or if we're performing an array new with an unknown
// bound.
- // FIXME: This needs to detect holes left by designated initializers too.
if ((maxElementsKnown && elementIndex < maxElements) ||
Entity.isVariableLengthArrayNew())
CheckEmptyInitializable(
@@ -1915,7 +1995,7 @@ void InitListChecker::CheckStructUnionTypes(
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList, unsigned &StructuredIndex,
bool TopLevelObject) {
- RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl();
// If the record is invalid, some of it's members are invalid. To avoid
// confusion, we forgo checking the intializer for the entire record.
@@ -1927,7 +2007,7 @@ void InitListChecker::CheckStructUnionTypes(
}
if (DeclType->isUnionType() && IList->getNumInits() == 0) {
- RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
if (!VerifyOnly)
for (FieldDecl *FD : RD->fields()) {
@@ -1939,8 +2019,9 @@ void InitListChecker::CheckStructUnionTypes(
}
// If there's a default initializer, use it.
- if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->hasInClassInitializer()) {
- if (VerifyOnly)
+ if (isa<CXXRecordDecl>(RD) &&
+ cast<CXXRecordDecl>(RD)->hasInClassInitializer()) {
+ if (!StructuredList)
return;
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
@@ -1957,11 +2038,10 @@ void InitListChecker::CheckStructUnionTypes(
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
if (!Field->isUnnamedBitfield()) {
- if (VerifyOnly)
- CheckEmptyInitializable(
- InitializedEntity::InitializeMember(*Field, &Entity),
- IList->getEndLoc());
- else
+ CheckEmptyInitializable(
+ InitializedEntity::InitializeMember(*Field, &Entity),
+ IList->getEndLoc());
+ if (StructuredList)
StructuredList->setInitializedFieldInUnion(*Field);
break;
}
@@ -1987,7 +2067,7 @@ void InitListChecker::CheckStructUnionTypes(
CheckSubElementType(BaseEntity, IList, Base.getType(), Index,
StructuredList, StructuredIndex);
InitializedSomething = true;
- } else if (VerifyOnly) {
+ } else {
CheckEmptyInitializable(BaseEntity, InitLoc);
}
@@ -2002,7 +2082,7 @@ 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->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
bool CheckForMissingFields =
!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
@@ -2095,7 +2175,7 @@ void InitListChecker::CheckStructUnionTypes(
StructuredList, StructuredIndex);
InitializedSomething = true;
- if (DeclType->isUnionType() && !VerifyOnly) {
+ if (DeclType->isUnionType() && StructuredList) {
// Initialize the first field within the union.
StructuredList->setInitializedFieldInUnion(*Field);
}
@@ -2119,10 +2199,10 @@ void InitListChecker::CheckStructUnionTypes(
}
}
- // Check that any remaining fields can be value-initialized.
- if (VerifyOnly && Field != FieldEnd && !DeclType->isUnionType() &&
+ // 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() &&
!Field->getType()->isIncompleteArrayType()) {
- // FIXME: Should check for holes left by designated initializers too.
for (; Field != FieldEnd && !hadError; ++Field) {
if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer())
CheckEmptyInitializable(
@@ -2227,7 +2307,7 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<FieldInitializerValidatorCCC>(*this);
+ return std::make_unique<FieldInitializerValidatorCCC>(*this);
}
private:
@@ -2257,7 +2337,9 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
///
/// @param NextField If non-NULL and the first designator in @p DIE is
/// a field, this will be set to the field declaration corresponding
-/// to the field named by the designator.
+/// to the field named by the designator. On input, this is expected to be
+/// the next field that would be initialized in the absence of designation,
+/// if the complete object being initialized is a struct.
///
/// @param NextElementIndex If non-NULL and the first designator in @p
/// DIE is an array designator or GNU array-range designator, this
@@ -2285,6 +2367,29 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
bool FinishSubobjectInit,
bool TopLevelObject) {
if (DesigIdx == DIE->size()) {
+ // C++20 designated initialization can result in direct-list-initialization
+ // of the designated subobject. This is the only way that we can end up
+ // performing direct initialization as part of aggregate initialization, so
+ // it needs special handling.
+ if (DIE->isDirectInit()) {
+ Expr *Init = DIE->getInit();
+ assert(isa<InitListExpr>(Init) &&
+ "designator result in direct non-list initialization?");
+ InitializationKind Kind = InitializationKind::CreateDirectList(
+ DIE->getBeginLoc(), Init->getBeginLoc(), Init->getEndLoc());
+ InitializationSequence Seq(SemaRef, Entity, Kind, Init,
+ /*TopLevelOfInitList*/ true);
+ if (StructuredList) {
+ ExprResult Result = VerifyOnly
+ ? getDummyInit()
+ : Seq.Perform(SemaRef, Entity, Kind, Init);
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ Result.get());
+ }
+ ++Index;
+ return !Seq;
+ }
+
// Check the actual initialization for the designated object type.
bool prevHadError = hadError;
@@ -2308,14 +2413,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx);
bool IsFirstDesignator = (DesigIdx == 0);
- if (!VerifyOnly) {
- assert((IsFirstDesignator || StructuredList) &&
- "Need a non-designated initializer list to start from");
-
+ if (IsFirstDesignator ? FullyStructuredList : StructuredList) {
// Determine the structural initializer list that corresponds to the
// current subobject.
if (IsFirstDesignator)
- StructuredList = SyntacticToSemantic.lookup(IList);
+ StructuredList = FullyStructuredList;
else {
Expr *ExistingInit = StructuredIndex < StructuredList->getNumInits() ?
StructuredList->getInit(StructuredIndex) : nullptr;
@@ -2329,48 +2431,42 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit))
StructuredList = Result;
else {
- if (DesignatedInitUpdateExpr *E =
- dyn_cast<DesignatedInitUpdateExpr>(ExistingInit))
- StructuredList = E->getUpdater();
- else {
- DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context)
- DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(),
- ExistingInit, DIE->getEndLoc());
- StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE);
- StructuredList = DIUE->getUpdater();
- }
-
- // We need to check on source range validity because the previous
- // initializer does not have to be an explicit initializer. e.g.,
+ // We are creating an initializer list that initializes the
+ // subobjects of the current object, but there was already an
+ // initialization that completely initialized the current
+ // subobject, e.g., by a compound literal:
//
- // struct P { int a, b; };
- // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
+ // struct X { int a, b; };
+ // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
//
- // There is an overwrite taking place because the first braced initializer
- // list "{ .a = 2 }" already provides value for .p.b (which is zero).
- if (ExistingInit->getSourceRange().isValid()) {
- // We are creating an initializer list that initializes the
- // subobjects of the current object, but there was already an
- // initialization that completely initialized the current
- // subobject, e.g., by a compound literal:
- //
- // struct X { int a, b; };
- // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
- //
- // Here, xs[0].a == 0 and xs[0].b == 3, since the second,
- // designated initializer re-initializes the whole
- // subobject [0], overwriting previous initializers.
- SemaRef.Diag(D->getBeginLoc(),
- diag::warn_subobject_initializer_overrides)
- << SourceRange(D->getBeginLoc(), DIE->getEndLoc());
-
- SemaRef.Diag(ExistingInit->getBeginLoc(),
- diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0 << ExistingInit->getSourceRange();
+ // Here, xs[0].a == 1 and xs[0].b == 3, since the second,
+ // designated initializer re-initializes only its current object
+ // subobject [0].b.
+ diagnoseInitOverride(ExistingInit,
+ SourceRange(D->getBeginLoc(), DIE->getEndLoc()),
+ /*FullyOverwritten=*/false);
+
+ if (!VerifyOnly) {
+ if (DesignatedInitUpdateExpr *E =
+ dyn_cast<DesignatedInitUpdateExpr>(ExistingInit))
+ StructuredList = E->getUpdater();
+ else {
+ DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context)
+ DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(),
+ ExistingInit, DIE->getEndLoc());
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE);
+ StructuredList = DIUE->getUpdater();
+ }
+ } else {
+ // We don't need to track the structured representation of a
+ // designated init update of an already-fully-initialized object in
+ // verify-only mode. The only reason we would need the structure is
+ // to determine where the uninitialized "holes" are, and in this
+ // case, we know there aren't any and we can't introduce any.
+ StructuredList = nullptr;
}
}
}
- assert(StructuredList && "Expected a structured initializer list");
}
if (D->isFieldDesignator()) {
@@ -2453,10 +2549,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
}
}
- unsigned FieldIndex = 0;
-
+ unsigned NumBases = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- FieldIndex = CXXRD->getNumBases();
+ NumBases = CXXRD->getNumBases();
+
+ unsigned FieldIndex = NumBases;
for (auto *FI : RT->getDecl()->fields()) {
if (FI->isUnnamedBitfield())
@@ -2475,7 +2572,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// the initializer list.
if (RT->getDecl()->isUnion()) {
FieldIndex = 0;
- if (!VerifyOnly) {
+ if (StructuredList) {
FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion();
if (CurrentField && !declaresSameEntity(CurrentField, *Field)) {
assert(StructuredList->getNumInits() == 1
@@ -2484,13 +2581,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
Expr *ExistingInit = StructuredList->getInit(0);
if (ExistingInit) {
// We're about to throw away an initializer, emit warning.
- SemaRef.Diag(D->getFieldLoc(),
- diag::warn_initializer_overrides)
- << D->getSourceRange();
- SemaRef.Diag(ExistingInit->getBeginLoc(),
- diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0
- << ExistingInit->getSourceRange();
+ diagnoseInitOverride(
+ ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc()));
}
// remove existing initializer
@@ -2513,16 +2605,63 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
return true;
}
- if (!VerifyOnly) {
- // Update the designator with the field declaration.
- D->setField(*Field);
+ // C++20 [dcl.init.list]p3:
+ // The ordered identifiers in the designators of the designated-
+ // initializer-list shall form a subsequence of the ordered identifiers
+ // in the direct non-static data members of T.
+ //
+ // Note that this is not a condition on forming the aggregate
+ // initialization, only on actually performing initialization,
+ // so it is not checked in VerifyOnly mode.
+ //
+ // FIXME: This is the only reordering diagnostic we produce, and it only
+ // catches cases where we have a top-level field designator that jumps
+ // backwards. This is the only such case that is reachable in an
+ // otherwise-valid C++20 program, so is the only case that's required for
+ // conformance, but for consistency, we should diagnose all the other
+ // cases where a designator takes us backwards too.
+ if (IsFirstDesignator && !VerifyOnly && SemaRef.getLangOpts().CPlusPlus &&
+ NextField &&
+ (*NextField == RT->getDecl()->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) {
+ if (FI->isUnnamedBitfield())
+ continue;
+ if (*NextField != RT->getDecl()->field_end() &&
+ declaresSameEntity(*FI, **NextField))
+ break;
+ PrevField = *FI;
+ }
- // Make sure that our non-designated initializer list has space
- // for a subobject corresponding to this field.
- if (FieldIndex >= StructuredList->getNumInits())
- StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1);
+ if (PrevField &&
+ PrevField->getFieldIndex() > KnownField->getFieldIndex()) {
+ SemaRef.Diag(DIE->getBeginLoc(), diag::ext_designated_init_reordered)
+ << KnownField << PrevField << DIE->getSourceRange();
+
+ unsigned OldIndex = NumBases + PrevField->getFieldIndex();
+ if (StructuredList && OldIndex <= StructuredList->getNumInits()) {
+ if (Expr *PrevInit = StructuredList->getInit(OldIndex)) {
+ SemaRef.Diag(PrevInit->getBeginLoc(),
+ diag::note_previous_field_init)
+ << PrevField << PrevInit->getSourceRange();
+ }
+ }
+ }
}
+
+ // Update the designator with the field declaration.
+ if (!VerifyOnly)
+ D->setField(*Field);
+
+ // Make sure that our non-designated initializer list has space
+ // for a subobject corresponding to this field.
+ if (StructuredList && FieldIndex >= StructuredList->getNumInits())
+ StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1);
+
// This designator names a flexible array member.
if (Field->getType()->isIncompleteArrayType()) {
bool Invalid = false;
@@ -2707,7 +2846,13 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
DesignatedEndIndex.setIsUnsigned(true);
}
- if (!VerifyOnly && StructuredList->isStringLiteralInit()) {
+ bool IsStringLiteralInitUpdate =
+ StructuredList && StructuredList->isStringLiteralInit();
+ if (IsStringLiteralInitUpdate && VerifyOnly) {
+ // We're just verifying an update to a string literal init. We don't need
+ // to split the string up into individual characters to do that.
+ StructuredList = nullptr;
+ } else if (IsStringLiteralInitUpdate) {
// We're modifying a string literal init; we have to decompose the string
// so we can modify the individual characters.
ASTContext &Context = SemaRef.Context;
@@ -2767,7 +2912,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this array element.
- if (!VerifyOnly &&
+ if (StructuredList &&
DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits())
StructuredList->resizeInits(SemaRef.Context,
DesignatedEndIndex.getZExtValue() + 1);
@@ -2829,12 +2974,11 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
unsigned StructuredIndex,
SourceRange InitRange,
bool IsFullyOverwritten) {
- if (VerifyOnly)
- return nullptr; // No structured list in verification-only mode.
- Expr *ExistingInit = nullptr;
if (!StructuredList)
- ExistingInit = SyntacticToSemantic.lookup(IList);
- else if (StructuredIndex < StructuredList->getNumInits())
+ return nullptr;
+
+ Expr *ExistingInit = nullptr;
+ if (StructuredIndex < StructuredList->getNumInits())
ExistingInit = StructuredList->getInit(StructuredIndex);
if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
@@ -2853,21 +2997,46 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
// We are creating an initializer list that initializes the
// subobjects of the current object, but there was already an
// initialization that completely initialized the current
- // subobject, e.g., by a compound literal:
+ // subobject:
//
// struct X { int a, b; };
+ // struct X xs[] = { [0] = { 1, 2 }, [0].b = 3 };
+ //
+ // Here, xs[0].a == 1 and xs[0].b == 3, since the second,
+ // designated initializer overwrites the [0].b initializer
+ // from the prior initialization.
+ //
+ // When the existing initializer is an expression rather than an
+ // initializer list, we cannot decompose and update it in this way.
+ // For example:
+ //
// struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
//
- // Here, xs[0].a == 0 and xs[0].b == 3, since the second,
- // designated initializer re-initializes the whole
- // subobject [0], overwriting previous initializers.
- SemaRef.Diag(InitRange.getBegin(),
- diag::warn_subobject_initializer_overrides)
- << InitRange;
- SemaRef.Diag(ExistingInit->getBeginLoc(), diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0 << ExistingInit->getSourceRange();
+ // This case is handled by CheckDesignatedInitializer.
+ diagnoseInitOverride(ExistingInit, InitRange);
}
+ unsigned ExpectedNumInits = 0;
+ if (Index < IList->getNumInits()) {
+ if (auto *Init = dyn_cast_or_null<InitListExpr>(IList->getInit(Index)))
+ ExpectedNumInits = Init->getNumInits();
+ else
+ ExpectedNumInits = IList->getNumInits() - Index;
+ }
+
+ InitListExpr *Result =
+ createInitListExpr(CurrentObjectType, InitRange, ExpectedNumInits);
+
+ // Link this new initializer list into the structured initializer
+ // lists.
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
+ return Result;
+}
+
+InitListExpr *
+InitListChecker::createInitListExpr(QualType CurrentObjectType,
+ SourceRange InitRange,
+ unsigned ExpectedNumInits) {
InitListExpr *Result
= new (SemaRef.Context) InitListExpr(SemaRef.Context,
InitRange.getBegin(), None,
@@ -2880,17 +3049,6 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
// Pre-allocate storage for the structured initializer list.
unsigned NumElements = 0;
- unsigned NumInits = 0;
- bool GotNumInits = false;
- if (!StructuredList) {
- NumInits = IList->getNumInits();
- GotNumInits = true;
- } else if (Index < IList->getNumInits()) {
- if (InitListExpr *SubList = dyn_cast<InitListExpr>(IList->getInit(Index))) {
- NumInits = SubList->getNumInits();
- GotNumInits = true;
- }
- }
if (const ArrayType *AType
= SemaRef.Context.getAsArrayType(CurrentObjectType)) {
@@ -2898,30 +3056,17 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
NumElements = CAType->getSize().getZExtValue();
// Simple heuristic so that we don't allocate a very large
// initializer with many empty entries at the end.
- if (GotNumInits && NumElements > NumInits)
+ if (NumElements > ExpectedNumInits)
NumElements = 0;
}
- } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>())
+ } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>()) {
NumElements = VType->getNumElements();
- else if (const RecordType *RType = CurrentObjectType->getAs<RecordType>()) {
- RecordDecl *RDecl = RType->getDecl();
- if (RDecl->isUnion())
- NumElements = 1;
- else
- NumElements = std::distance(RDecl->field_begin(), RDecl->field_end());
+ } else if (CurrentObjectType->isRecordType()) {
+ NumElements = numStructUnionElements(CurrentObjectType);
}
Result->reserveInits(SemaRef.Context, NumElements);
- // Link this new initializer list into the structured initializer
- // lists.
- if (StructuredList)
- StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
- else {
- Result->setSyntacticForm(IList);
- SyntacticToSemantic[IList] = Result;
- }
-
return Result;
}
@@ -2937,24 +3082,23 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context,
StructuredIndex, expr)) {
// This initializer overwrites a previous initializer. Warn.
- // We need to check on source range validity because the previous
- // initializer does not have to be an explicit initializer.
- // struct P { int a, b; };
- // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
- // There is an overwrite taking place because the first braced initializer
- // list "{ .a = 2 }' already provides value for .p.b (which is zero).
- if (PrevInit->getSourceRange().isValid()) {
- SemaRef.Diag(expr->getBeginLoc(), diag::warn_initializer_overrides)
- << expr->getSourceRange();
-
- SemaRef.Diag(PrevInit->getBeginLoc(), diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0 << PrevInit->getSourceRange();
- }
+ diagnoseInitOverride(PrevInit, expr->getSourceRange());
}
++StructuredIndex;
}
+/// Determine whether we can perform aggregate initialization for the purposes
+/// of overload resolution.
+bool Sema::CanPerformAggregateInitializationForOverloadResolution(
+ const InitializedEntity &Entity, InitListExpr *From) {
+ QualType Type = Entity.getType();
+ InitListChecker Check(*this, Entity, From, Type, /*VerifyOnly=*/true,
+ /*TreatUnavailableAsInvalid=*/false,
+ /*InOverloadResolution=*/true);
+ return !Check.HadError();
+}
+
/// Check that the given Index expression is a valid array designator
/// value. This is essentially just a wrapper around
/// VerifyIntegerConstantExpression that also checks for negative values
@@ -2980,7 +3124,7 @@ CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) {
}
ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
- SourceLocation Loc,
+ SourceLocation EqualOrColonLoc,
bool GNUSyntax,
ExprResult Init) {
typedef DesignatedInitExpr::Designator ASTDesignator;
@@ -3065,17 +3209,9 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
// Clear out the expressions within the designation.
Desig.ClearExprs(*this);
- DesignatedInitExpr *DIE
- = DesignatedInitExpr::Create(Context,
- Designators,
- InitExpressions, Loc, GNUSyntax,
- Init.getAs<Expr>());
-
- if (!getLangOpts().C99)
- Diag(DIE->getBeginLoc(), diag::ext_designated_init)
- << DIE->getSourceRange();
-
- return DIE;
+ return DesignatedInitExpr::Create(Context, Designators, InitExpressions,
+ EqualOrColonLoc, GNUSyntax,
+ Init.getAs<Expr>());
}
//===----------------------------------------------------------------------===//
@@ -3691,9 +3827,10 @@ static bool TryInitializerListConstruction(Sema &S,
// Try initializing a temporary array from the init list.
QualType ArrayType = S.Context.getConstantArrayType(
- E.withConst(), llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
- List->getNumInits()),
- clang::ArrayType::Normal, 0);
+ E.withConst(),
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ List->getNumInits()),
+ nullptr, clang::ArrayType::Normal, 0);
InitializedEntity HiddenArray =
InitializedEntity::InitializeTemporary(ArrayType);
InitializationKind Kind = InitializationKind::CreateDirectList(
@@ -4070,7 +4207,7 @@ static void TryReferenceListInitialization(Sema &S,
}
QualType DestType = Entity.getType();
- QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
@@ -4092,10 +4229,10 @@ static void TryReferenceListInitialization(Sema &S,
return;
SourceLocation DeclLoc = Initializer->getBeginLoc();
- bool dummy1, dummy2, dummy3;
+ bool dummy1, dummy2, dummy3, dummy4;
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
- dummy2, dummy3);
+ dummy2, dummy3, dummy4);
if (RefRelationship >= Sema::Ref_Related) {
// Try to bind the reference here.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
@@ -4327,7 +4464,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
Expr *Initializer, bool AllowRValues, bool IsLValueRef,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
- QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
QualType T1 = cv1T1.getUnqualifiedType();
QualType cv2T2 = Initializer->getType();
QualType T2 = cv2T2.getUnqualifiedType();
@@ -4335,13 +4472,15 @@ static OverloadingResult TryRefInitWithConversionFunction(
bool DerivedToBase;
bool ObjCConversion;
bool ObjCLifetimeConversion;
- assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2,
- DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion) &&
+ bool FunctionConversion;
+ assert(!S.CompareReferenceRelationship(
+ Initializer->getBeginLoc(), T1, T2, DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion, FunctionConversion) &&
"Must have incompatible references when binding via conversion");
(void)DerivedToBase;
(void)ObjCConversion;
(void)ObjCLifetimeConversion;
+ (void)FunctionConversion;
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
@@ -4468,10 +4607,11 @@ static OverloadingResult TryRefInitWithConversionFunction(
bool NewDerivedToBase = false;
bool NewObjCConversion = false;
bool NewObjCLifetimeConversion = false;
- Sema::ReferenceCompareResult NewRefRelationship
- = S.CompareReferenceRelationship(DeclLoc, T1, cv3T3,
- NewDerivedToBase, NewObjCConversion,
- NewObjCLifetimeConversion);
+ bool NewFunctionConversion = false;
+ Sema::ReferenceCompareResult NewRefRelationship =
+ S.CompareReferenceRelationship(
+ DeclLoc, T1, cv3T3, NewDerivedToBase, NewObjCConversion,
+ NewObjCLifetimeConversion, NewFunctionConversion);
// Add the final conversion sequence, if necessary.
if (NewRefRelationship == Sema::Ref_Incompatible) {
@@ -4505,6 +4645,8 @@ static OverloadingResult TryRefInitWithConversionFunction(
Sequence.AddDerivedToBaseCastStep(cv1T1, VK);
else if (NewObjCConversion)
Sequence.AddObjCObjectConversionStep(cv1T1);
+ else if (NewFunctionConversion)
+ Sequence.AddQualificationConversionStep(cv1T1, VK);
return OR_Success;
}
@@ -4520,7 +4662,7 @@ static void TryReferenceInitialization(Sema &S,
Expr *Initializer,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
- QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
QualType cv2T2 = Initializer->getType();
@@ -4564,10 +4706,11 @@ static void TryReferenceInitializationCore(Sema &S,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
+ bool FunctionConversion = false;
Expr::Classification InitCategory = Initializer->Classify(S.Context);
- Sema::ReferenceCompareResult RefRelationship
- = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion);
+ Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
+ DeclLoc, cv1T1, cv2T2, DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion, FunctionConversion);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression of type
@@ -4598,6 +4741,8 @@ static void TryReferenceInitializationCore(Sema &S,
Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
else if (ObjCConversion)
Sequence.AddObjCObjectConversionStep(cv1T1);
+ else if (FunctionConversion)
+ Sequence.AddQualificationConversionStep(cv1T1, VK_LValue);
// We only create a temporary here when binding a reference to a
// bit-field or vector element. Those cases are't supposed to be
@@ -6233,8 +6378,11 @@ PerformConstructorInitialization(Sema &S,
// the definition for completely trivial constructors.
assert(Constructor->getParent() && "No parent class for constructor.");
if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
- Constructor->isTrivial() && !Constructor->isUsed(false))
- S.DefineImplicitDefaultConstructor(Loc, Constructor);
+ Constructor->isTrivial() && !Constructor->isUsed(false)) {
+ S.runWithSufficientStackSpace(Loc, [&] {
+ S.DefineImplicitDefaultConstructor(Loc, Constructor);
+ });
+ }
}
ExprResult CurInit((Expr *)nullptr);
@@ -6505,6 +6653,7 @@ struct IndirectLocalPathEntry {
VarInit,
LValToRVal,
LifetimeBoundCall,
+ GslPointerInit
} Kind;
Expr *E;
const Decl *D = nullptr;
@@ -6543,11 +6692,138 @@ static bool pathContainsInit(IndirectLocalPath &Path) {
static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *Init, LocalVisitor Visit,
- bool RevisitSubinits);
+ bool RevisitSubinits,
+ bool EnableLifetimeWarnings);
static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
- LocalVisitor Visit);
+ LocalVisitor Visit,
+ bool EnableLifetimeWarnings);
+
+template <typename T> static bool isRecordWithAttr(QualType Type) {
+ if (auto *RD = Type->getAsCXXRecordDecl())
+ return RD->hasAttr<T>();
+ return false;
+}
+
+// Decl::isInStdNamespace will return false for iterators in some STL
+// implementations due to them being defined in a namespace outside of the std
+// namespace.
+static bool isInStlNamespace(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ if (!DC)
+ return false;
+ if (const auto *ND = dyn_cast<NamespaceDecl>(DC))
+ if (const IdentifierInfo *II = ND->getIdentifier()) {
+ StringRef Name = II->getName();
+ if (Name.size() >= 2 && Name.front() == '_' &&
+ (Name[1] == '_' || isUppercase(Name[1])))
+ return true;
+ }
+
+ return DC->isStdNamespace();
+}
+
+static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
+ if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
+ if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()))
+ return true;
+ if (!isInStlNamespace(Callee->getParent()))
+ return false;
+ if (!isRecordWithAttr<PointerAttr>(Callee->getThisObjectType()) &&
+ !isRecordWithAttr<OwnerAttr>(Callee->getThisObjectType()))
+ return false;
+ if (Callee->getReturnType()->isPointerType() ||
+ isRecordWithAttr<PointerAttr>(Callee->getReturnType())) {
+ if (!Callee->getIdentifier())
+ return false;
+ return llvm::StringSwitch<bool>(Callee->getName())
+ .Cases("begin", "rbegin", "cbegin", "crbegin", true)
+ .Cases("end", "rend", "cend", "crend", true)
+ .Cases("c_str", "data", "get", true)
+ // Map and set types.
+ .Cases("find", "equal_range", "lower_bound", "upper_bound", true)
+ .Default(false);
+ } else if (Callee->getReturnType()->isReferenceType()) {
+ if (!Callee->getIdentifier()) {
+ auto OO = Callee->getOverloadedOperator();
+ return OO == OverloadedOperatorKind::OO_Subscript ||
+ OO == OverloadedOperatorKind::OO_Star;
+ }
+ return llvm::StringSwitch<bool>(Callee->getName())
+ .Cases("front", "back", "at", "top", "value", true)
+ .Default(false);
+ }
+ return false;
+}
+
+static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
+ if (!FD->getIdentifier() || FD->getNumParams() != 1)
+ return false;
+ const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();
+ if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace())
+ return false;
+ if (!isRecordWithAttr<PointerAttr>(QualType(RD->getTypeForDecl(), 0)) &&
+ !isRecordWithAttr<OwnerAttr>(QualType(RD->getTypeForDecl(), 0)))
+ return false;
+ if (FD->getReturnType()->isPointerType() ||
+ isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
+ return llvm::StringSwitch<bool>(FD->getName())
+ .Cases("begin", "rbegin", "cbegin", "crbegin", true)
+ .Cases("end", "rend", "cend", "crend", true)
+ .Case("data", true)
+ .Default(false);
+ } else if (FD->getReturnType()->isReferenceType()) {
+ return llvm::StringSwitch<bool>(FD->getName())
+ .Cases("get", "any_cast", true)
+ .Default(false);
+ }
+ return false;
+}
+
+static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
+ LocalVisitor Visit) {
+ auto VisitPointerArg = [&](const Decl *D, Expr *Arg) {
+ // We are not interested in the temporary base objects of gsl Pointers:
+ // Temp().ptr; // Here ptr might not dangle.
+ if (isa<MemberExpr>(Arg->IgnoreImpCasts()))
+ return;
+ Path.push_back({IndirectLocalPathEntry::GslPointerInit, Arg, D});
+ if (Arg->isGLValue())
+ visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
+ Visit,
+ /*EnableLifetimeWarnings=*/true);
+ else
+ visitLocalsRetainedByInitializer(Path, Arg, Visit, true,
+ /*EnableLifetimeWarnings=*/true);
+ Path.pop_back();
+ };
+
+ if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
+ const auto *MD = cast_or_null<CXXMethodDecl>(MCE->getDirectCallee());
+ if (MD && shouldTrackImplicitObjectArg(MD))
+ VisitPointerArg(MD, MCE->getImplicitObjectArgument());
+ return;
+ } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call)) {
+ FunctionDecl *Callee = OCE->getDirectCallee();
+ if (Callee && Callee->isCXXInstanceMember() &&
+ shouldTrackImplicitObjectArg(cast<CXXMethodDecl>(Callee)))
+ VisitPointerArg(Callee, OCE->getArg(0));
+ return;
+ } else if (auto *CE = dyn_cast<CallExpr>(Call)) {
+ FunctionDecl *Callee = CE->getDirectCallee();
+ if (Callee && shouldTrackFirstArgument(Callee))
+ VisitPointerArg(Callee, CE->getArg(0));
+ return;
+ }
+
+ if (auto *CCE = dyn_cast<CXXConstructExpr>(Call)) {
+ const auto *Ctor = CCE->getConstructor();
+ const CXXRecordDecl *RD = Ctor->getParent();
+ if (CCE->getNumArgs() > 0 && RD->hasAttr<PointerAttr>())
+ VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0]);
+ }
+}
static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
@@ -6594,9 +6870,11 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
Path.push_back({IndirectLocalPathEntry::LifetimeBoundCall, Arg, D});
if (Arg->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
- Visit);
+ Visit,
+ /*EnableLifetimeWarnings=*/false);
else
- visitLocalsRetainedByInitializer(Path, Arg, Visit, true);
+ visitLocalsRetainedByInitializer(Path, Arg, Visit, true,
+ /*EnableLifetimeWarnings=*/false);
Path.pop_back();
};
@@ -6615,7 +6893,8 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
/// glvalue expression \c Init.
static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
- LocalVisitor Visit) {
+ LocalVisitor Visit,
+ bool EnableLifetimeWarnings) {
RevertToOldSizeRAII RAII(Path);
// Walk past any constructs which we can lifetime-extend across.
@@ -6652,7 +6931,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
else
// We can't lifetime extend through this but we might still find some
// retained temporaries.
- return visitLocalsRetainedByInitializer(Path, Init, Visit, true);
+ return visitLocalsRetainedByInitializer(Path, Init, Visit, true,
+ EnableLifetimeWarnings);
}
// Step into CXXDefaultInitExprs so we can diagnose cases where a
@@ -6667,11 +6947,14 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {
if (Visit(Path, Local(MTE), RK))
visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), Visit,
- true);
+ true, EnableLifetimeWarnings);
}
- if (isa<CallExpr>(Init))
+ if (isa<CallExpr>(Init)) {
+ if (EnableLifetimeWarnings)
+ handleGslAnnotatedTypes(Path, Init, Visit);
return visitLifetimeBoundArguments(Path, Init, Visit);
+ }
switch (Init->getStmtClass()) {
case Stmt::DeclRefExprClass: {
@@ -6690,7 +6973,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
} else if (VD->getInit() && !isVarOnPath(Path, VD)) {
Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
visitLocalsRetainedByReferenceBinding(Path, VD->getInit(),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
}
}
break;
@@ -6702,13 +6986,15 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
// handling all sorts of rvalues passed to a unary operator.
const UnaryOperator *U = cast<UnaryOperator>(Init);
if (U->getOpcode() == UO_Deref)
- visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true,
+ EnableLifetimeWarnings);
break;
}
case Stmt::OMPArraySectionExprClass: {
- visitLocalsRetainedByInitializer(
- Path, cast<OMPArraySectionExpr>(Init)->getBase(), Visit, true);
+ visitLocalsRetainedByInitializer(Path,
+ cast<OMPArraySectionExpr>(Init)->getBase(),
+ Visit, true, EnableLifetimeWarnings);
break;
}
@@ -6716,9 +7002,11 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
case Stmt::BinaryConditionalOperatorClass: {
auto *C = cast<AbstractConditionalOperator>(Init);
if (!C->getTrueExpr()->getType()->isVoidType())
- visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit);
+ visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit,
+ EnableLifetimeWarnings);
if (!C->getFalseExpr()->getType()->isVoidType())
- visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit);
+ visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit,
+ EnableLifetimeWarnings);
break;
}
@@ -6733,7 +7021,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
/// the prvalue expression \c Init.
static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *Init, LocalVisitor Visit,
- bool RevisitSubinits) {
+ bool RevisitSubinits,
+ bool EnableLifetimeWarnings) {
RevertToOldSizeRAII RAII(Path);
Expr *Old;
@@ -6773,15 +7062,17 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
if (VD && VD->getType().isConstQualified() && VD->getInit() &&
!isVarOnPath(Path, VD)) {
Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
- visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true,
+ EnableLifetimeWarnings);
}
} else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) {
if (MTE->getType().isConstQualified())
visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(),
- Visit, true);
+ Visit, true,
+ EnableLifetimeWarnings);
}
return false;
- });
+ }, EnableLifetimeWarnings);
// We assume that objects can be retained by pointers cast to integers,
// but not if the integer is cast to floating-point type or to _Complex.
@@ -6811,7 +7102,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
// lvalue.
Path.push_back({IndirectLocalPathEntry::AddressOf, CE});
return visitLocalsRetainedByReferenceBinding(Path, CE->getSubExpr(),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
default:
return;
@@ -6826,7 +7118,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
// lifetime of the array exactly like binding a reference to a temporary.
if (auto *ILE = dyn_cast<CXXStdInitializerListExpr>(Init))
return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(),
- RK_StdInitializerList, Visit);
+ RK_StdInitializerList, Visit,
+ EnableLifetimeWarnings);
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
// We already visited the elements of this initializer list while
@@ -6837,12 +7130,14 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
if (ILE->isTransparent())
return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
if (ILE->getType()->isArrayType()) {
for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
return;
}
@@ -6855,12 +7150,14 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
else {
unsigned Index = 0;
for (; Index < RD->getNumBases() && Index < ILE->getNumInits(); ++Index)
visitLocalsRetainedByInitializer(Path, ILE->getInit(Index), Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
for (const auto *I : RD->fields()) {
if (Index >= ILE->getNumInits())
break;
@@ -6869,13 +7166,15 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *SubInit = ILE->getInit(Index);
if (I->getType()->isReferenceType())
visitLocalsRetainedByReferenceBinding(Path, SubInit,
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
else
// This might be either aggregate-initialization of a member or
// initialization of a std::initializer_list object. Regardless,
// we should recursively lifetime-extend that initializer.
visitLocalsRetainedByInitializer(Path, SubInit, Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
++Index;
}
}
@@ -6891,14 +7190,18 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
continue;
if (E->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, E, RK_ReferenceBinding,
- Visit);
+ Visit, EnableLifetimeWarnings);
else
- visitLocalsRetainedByInitializer(Path, E, Visit, true);
+ visitLocalsRetainedByInitializer(Path, E, Visit, true,
+ EnableLifetimeWarnings);
}
}
- if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init))
+ if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init)) {
+ if (EnableLifetimeWarnings)
+ handleGslAnnotatedTypes(Path, Init, Visit);
return visitLifetimeBoundArguments(Path, Init, Visit);
+ }
switch (Init->getStmtClass()) {
case Stmt::UnaryOperatorClass: {
@@ -6914,7 +7217,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Path.push_back({IndirectLocalPathEntry::AddressOf, UO});
visitLocalsRetainedByReferenceBinding(Path, UO->getSubExpr(),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
}
break;
}
@@ -6927,9 +7231,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
break;
if (BO->getLHS()->getType()->isPointerType())
- visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true,
+ EnableLifetimeWarnings);
else if (BO->getRHS()->getType()->isPointerType())
- visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true,
+ EnableLifetimeWarnings);
break;
}
@@ -6939,9 +7245,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
// In C++, we can have a throw-expression operand, which has 'void' type
// and isn't interesting from a lifetime perspective.
if (!C->getTrueExpr()->getType()->isVoidType())
- visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true,
+ EnableLifetimeWarnings);
if (!C->getFalseExpr()->getType()->isVoidType())
- visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true,
+ EnableLifetimeWarnings);
break;
}
@@ -6980,18 +7288,33 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
case IndirectLocalPathEntry::AddressOf:
case IndirectLocalPathEntry::LValToRVal:
case IndirectLocalPathEntry::LifetimeBoundCall:
+ case IndirectLocalPathEntry::GslPointerInit:
// These exist primarily to mark the path as not permitting or
// supporting lifetime extension.
break;
- case IndirectLocalPathEntry::DefaultInit:
case IndirectLocalPathEntry::VarInit:
+ if (cast<VarDecl>(Path[I].D)->isImplicit())
+ return SourceRange();
+ LLVM_FALLTHROUGH;
+ case IndirectLocalPathEntry::DefaultInit:
return Path[I].E->getSourceRange();
}
}
return E->getSourceRange();
}
+static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) {
+ for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) {
+ if (It->Kind == IndirectLocalPathEntry::VarInit)
+ continue;
+ if (It->Kind == IndirectLocalPathEntry::AddressOf)
+ continue;
+ return It->Kind == IndirectLocalPathEntry::GslPointerInit;
+ }
+ return false;
+}
+
void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
Expr *Init) {
LifetimeResult LR = getEntityLifetime(&Entity);
@@ -7008,12 +7331,36 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
SourceRange DiagRange = nextPathEntryRange(Path, 0, L);
SourceLocation DiagLoc = DiagRange.getBegin();
+ auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
+
+ bool IsGslPtrInitWithGslTempOwner = false;
+ bool IsLocalGslOwner = false;
+ if (pathOnlyInitializesGslPointer(Path)) {
+ if (isa<DeclRefExpr>(L)) {
+ // We do not want to follow the references when returning a pointer originating
+ // from a local owner to avoid the following false positive:
+ // int &p = *localUniquePtr;
+ // someContainer.add(std::move(localUniquePtr));
+ // return p;
+ IsLocalGslOwner = isRecordWithAttr<OwnerAttr>(L->getType());
+ if (pathContainsInit(Path) || !IsLocalGslOwner)
+ return false;
+ } else {
+ IsGslPtrInitWithGslTempOwner = MTE && !MTE->getExtendingDecl() &&
+ isRecordWithAttr<OwnerAttr>(MTE->getType());
+ // Skipping a chain of initializing gsl::Pointer annotated objects.
+ // We are looking only for the final source to find out if it was
+ // a local or temporary owner or the address of a local variable/param.
+ if (!IsGslPtrInitWithGslTempOwner)
+ return true;
+ }
+ }
+
switch (LK) {
case LK_FullExpression:
llvm_unreachable("already handled this");
case LK_Extended: {
- auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
if (!MTE) {
// The initialized entity has lifetime beyond the full-expression,
// and the local entity does too, so don't warn.
@@ -7023,6 +7370,11 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
return false;
}
+ if (IsGslPtrInitWithGslTempOwner && DiagLoc.isValid()) {
+ Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange;
+ return false;
+ }
+
// Lifetime-extend the temporary.
if (Path.empty()) {
// Update the storage duration of the materialized temporary.
@@ -7064,6 +7416,14 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
// temporary, the program is ill-formed.
if (auto *ExtendingDecl =
ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {
+ if (IsGslPtrInitWithGslTempOwner) {
+ Diag(DiagLoc, diag::warn_dangling_lifetime_pointer_member)
+ << ExtendingDecl << DiagRange;
+ Diag(ExtendingDecl->getLocation(),
+ diag::note_ref_or_ptr_member_declared_here)
+ << true;
+ return false;
+ }
bool IsSubobjectMember = ExtendingEntity != &Entity;
Diag(DiagLoc, shouldLifetimeExtendThroughPath(Path)
? diag::err_dangling_member
@@ -7094,6 +7454,11 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
if (pathContainsInit(Path))
return false;
+ // Suppress false positives for code like the one below:
+ // Ctor(unique_ptr<T> up) : member(*up), member2(move(up)) {}
+ if (IsLocalGslOwner && pathOnlyInitializesGslPointer(Path))
+ return false;
+
auto *DRE = dyn_cast<DeclRefExpr>(L);
auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;
if (!VD) {
@@ -7104,7 +7469,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
if (auto *Member =
ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {
- bool IsPointer = Member->getType()->isAnyPointerType();
+ bool IsPointer = !Member->getType()->isReferenceType();
Diag(DiagLoc, IsPointer ? diag::warn_init_ptr_member_to_parameter_addr
: diag::warn_bind_ref_member_to_parameter)
<< Member << VD << isa<ParmVarDecl>(VD) << DiagRange;
@@ -7118,10 +7483,13 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
case LK_New:
if (isa<MaterializeTemporaryExpr>(L)) {
- Diag(DiagLoc, RK == RK_ReferenceBinding
- ? diag::warn_new_dangling_reference
- : diag::warn_new_dangling_initializer_list)
- << !Entity.getParent() << DiagRange;
+ if (IsGslPtrInitWithGslTempOwner)
+ Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange;
+ else
+ Diag(DiagLoc, RK == RK_ReferenceBinding
+ ? diag::warn_new_dangling_reference
+ : diag::warn_new_dangling_initializer_list)
+ << !Entity.getParent() << DiagRange;
} else {
// We can't determine if the allocation outlives the local declaration.
return false;
@@ -7164,7 +7532,8 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
break;
case IndirectLocalPathEntry::LifetimeBoundCall:
- // FIXME: Consider adding a note for this.
+ case IndirectLocalPathEntry::GslPointerInit:
+ // FIXME: Consider adding a note for these.
break;
case IndirectLocalPathEntry::DefaultInit: {
@@ -7189,12 +7558,16 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
return false;
};
+ bool EnableLifetimeWarnings = !getDiagnostics().isIgnored(
+ diag::warn_dangling_lifetime_pointer, SourceLocation());
llvm::SmallVector<IndirectLocalPathEntry, 8> Path;
if (Init->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding,
- TemporaryVisitor);
+ TemporaryVisitor,
+ EnableLifetimeWarnings);
else
- visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false);
+ visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false,
+ EnableLifetimeWarnings);
}
static void DiagnoseNarrowingInInitList(Sema &S,
@@ -7837,7 +8210,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
Ty = S.Context.getRValueReferenceType(Ty);
else if ((*ResultType)->isLValueReferenceType())
Ty = S.Context.getLValueReferenceType(Ty,
- (*ResultType)->getAs<LValueReferenceType>()->isSpelledAsLValue());
+ (*ResultType)->castAs<LValueReferenceType>()->isSpelledAsLValue());
*ResultType = Ty;
}
@@ -8043,6 +8416,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
*ResultType = S.Context.getConstantArrayType(
IncompleteDest->getElementType(),
ConstantSource->getSize(),
+ ConstantSource->getSizeExpr(),
ArrayType::Normal, 0);
}
}
@@ -8108,7 +8482,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
// argument passing.
assert(Step->Type->isSamplerT() &&
"Sampler initialization on non-sampler type.");
- Expr *Init = CurInit.get();
+ Expr *Init = CurInit.get()->IgnoreParens();
QualType SourceType = Init->getType();
// Case 1
if (Entity.isParameterKind()) {
@@ -8285,7 +8659,7 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,
E.withConst(),
llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
InitList->getNumInits()),
- clang::ArrayType::Normal, 0);
+ nullptr, clang::ArrayType::Normal, 0);
InitializedEntity HiddenArray =
InitializedEntity::InitializeTemporary(ArrayType);
return diagnoseListInit(S, HiddenArray, InitList);
@@ -8295,7 +8669,7 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,
// A list-initialization failure for a reference means that we tried to
// create a temporary of the inner type (per [dcl.init.list]p3.6) and the
// inner initialization failed.
- QualType T = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType T = DestType->castAs<ReferenceType>()->getPointeeType();
diagnoseListInit(S, InitializedEntity::InitializeTemporary(T), InitList);
SourceLocation Loc = InitList->getBeginLoc();
if (auto *D = Entity.getDecl())
@@ -8652,7 +9026,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< InheritedFrom;
RecordDecl *BaseDecl
- = Entity.getBaseSpecifier()->getType()->getAs<RecordType>()
+ = Entity.getBaseSpecifier()->getType()->castAs<RecordType>()
->getDecl();
S.Diag(BaseDecl->getLocation(), diag::note_previous_decl)
<< S.Context.getTagDeclType(BaseDecl);