aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/Decl.cpp8
-rw-r--r--clang/lib/AST/DeclCXX.cpp39
-rw-r--r--clang/lib/Sema/SemaDecl.cpp2
-rw-r--r--clang/lib/Sema/SemaInit.cpp58
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp4
6 files changed, 108 insertions, 4 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 31749e4..30341b0 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5031,6 +5031,7 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C,
setHasNonTrivialToPrimitiveDefaultInitializeCUnion(false);
setHasNonTrivialToPrimitiveDestructCUnion(false);
setHasNonTrivialToPrimitiveCopyCUnion(false);
+ setHasUninitializedExplicitInitFields(false);
setParamDestroyedInCallee(false);
setArgPassingRestrictions(RecordArgPassingKind::CanPassInRegs);
setIsRandomized(false);
@@ -5231,9 +5232,10 @@ unsigned RecordDecl::getODRHash() {
// Only calculate hash on first call of getODRHash per record.
ODRHash Hash;
Hash.AddRecordDecl(this);
- // For RecordDecl the ODRHash is stored in the remaining 26
- // bit of RecordDeclBits, adjust the hash to accomodate.
- setODRHash(Hash.CalculateHash() >> 6);
+ // For RecordDecl the ODRHash is stored in the remaining
+ // bits of RecordDeclBits, adjust the hash to accommodate.
+ static_assert(sizeof(Hash.CalculateHash()) * CHAR_BIT == 32);
+ setODRHash(Hash.CalculateHash() >> (32 - NumOdrHashBits));
return RecordDeclBits.ODRHash;
}
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 4163342..44f4589 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -29,6 +29,7 @@
#include "clang/AST/TypeLoc.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticAST.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
@@ -457,6 +458,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (BaseClassDecl->hasMutableFields())
data().HasMutableFields = true;
+ if (BaseClassDecl->hasUninitializedExplicitInitFields() &&
+ BaseClassDecl->isAggregate())
+ setHasUninitializedExplicitInitFields(true);
+
if (BaseClassDecl->hasUninitializedReferenceMember())
data().HasUninitializedReferenceMember = true;
@@ -1113,6 +1118,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
} else if (!T.isCXX98PODType(Context))
data().PlainOldData = false;
+ if (Field->hasAttr<ExplicitInitAttr>())
+ setHasUninitializedExplicitInitFields(true);
+
if (T->isReferenceType()) {
if (!Field->hasInClassInitializer())
data().HasUninitializedReferenceMember = true;
@@ -1372,6 +1380,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!FieldRec->hasCopyAssignmentWithConstParam())
data().ImplicitCopyAssignmentHasConstParam = false;
+ if (FieldRec->hasUninitializedExplicitInitFields() &&
+ FieldRec->isAggregate())
+ setHasUninitializedExplicitInitFields(true);
+
if (FieldRec->hasUninitializedReferenceMember() &&
!Field->hasInClassInitializer())
data().HasUninitializedReferenceMember = true;
@@ -2188,6 +2200,33 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
for (conversion_iterator I = conversion_begin(), E = conversion_end();
I != E; ++I)
I.setAccess((*I)->getAccess());
+
+ ASTContext &Context = getASTContext();
+
+ if (isAggregate() && hasUserDeclaredConstructor() &&
+ !Context.getLangOpts().CPlusPlus20) {
+ // Diagnose any aggregate behavior changes in C++20
+ for (const FieldDecl *FD : fields()) {
+ if (const auto *AT = FD->getAttr<ExplicitInitAttr>())
+ Context.getDiagnostics().Report(
+ AT->getLocation(),
+ diag::warn_cxx20_compat_requires_explicit_init_non_aggregate)
+ << AT << FD << Context.getRecordType(this);
+ }
+ }
+
+ if (!isAggregate() && hasUninitializedExplicitInitFields()) {
+ // Diagnose any fields that required explicit initialization in a
+ // non-aggregate type. (Note that the fields may not be directly in this
+ // type, but in a subobject. In such cases we don't emit diagnoses here.)
+ for (const FieldDecl *FD : fields()) {
+ if (const auto *AT = FD->getAttr<ExplicitInitAttr>())
+ Context.getDiagnostics().Report(AT->getLocation(),
+ diag::warn_attribute_needs_aggregate)
+ << AT << Context.getRecordType(this);
+ }
+ setHasUninitializedExplicitInitFields(false);
+ }
}
bool CXXRecordDecl::mayBeAbstract() const {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fd3a5ec..704cb82 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -19232,6 +19232,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
if (FT.hasNonTrivialToPrimitiveCopyCUnion() || Record->isUnion())
Record->setHasNonTrivialToPrimitiveCopyCUnion(true);
}
+ if (FD->hasAttr<ExplicitInitAttr>())
+ Record->setHasUninitializedExplicitInitFields(true);
if (FT.isDestructedType()) {
Record->setNonTrivialToPrimitiveDestroy(true);
Record->setParamDestroyedInCallee(true);
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 0dd5f46..b95cbbf 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -264,6 +264,13 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
updateStringLiteralType(Str, DeclT);
}
+void emitUninitializedExplicitInitFields(Sema &S, const RecordDecl *R) {
+ for (const FieldDecl *Field : R->fields()) {
+ if (Field->hasAttr<ExplicitInitAttr>())
+ S.Diag(Field->getLocation(), diag::note_entity_declared_at) << Field;
+ }
+}
+
//===----------------------------------------------------------------------===//
// Semantic checking for initializer lists.
//===----------------------------------------------------------------------===//
@@ -738,6 +745,14 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
ILE->updateInit(SemaRef.Context, Init, Filler);
return;
}
+
+ if (!VerifyOnly && Field->hasAttr<ExplicitInitAttr>()) {
+ SemaRef.Diag(ILE->getExprLoc(), diag::warn_field_requires_explicit_init)
+ << /* Var-in-Record */ 0 << Field;
+ SemaRef.Diag(Field->getLocation(), diag::note_entity_declared_at)
+ << Field;
+ }
+
// C++1y [dcl.init.aggr]p7:
// If there are fewer initializer-clauses in the list than there are
// members in the aggregate, then each member not explicitly initialized
@@ -4558,6 +4573,14 @@ static void TryConstructorInitialization(Sema &S,
CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
if (Result != OR_Deleted) {
+ if (!IsListInit && Kind.getKind() == InitializationKind::IK_Default &&
+ DestRecordDecl != nullptr && DestRecordDecl->isAggregate() &&
+ DestRecordDecl->hasUninitializedExplicitInitFields()) {
+ S.Diag(Kind.getLocation(), diag::warn_field_requires_explicit_init)
+ << /* Var-in-Record */ 1 << DestRecordDecl;
+ emitUninitializedExplicitInitFields(S, DestRecordDecl);
+ }
+
// C++11 [dcl.init]p6:
// If a program calls for the default initialization of an object
// of a const-qualified type T, T shall be a class type with a
@@ -5852,6 +5875,12 @@ static void TryOrBuildParenListInitialization(
} else {
// We've processed all of the args, but there are still members that
// have to be initialized.
+ if (!VerifyOnly && FD->hasAttr<ExplicitInitAttr>()) {
+ S.Diag(Kind.getLocation(), diag::warn_field_requires_explicit_init)
+ << /* Var-in-Record */ 0 << FD;
+ S.Diag(FD->getLocation(), diag::note_entity_declared_at) << FD;
+ }
+
if (FD->hasInClassInitializer()) {
if (!VerifyOnly) {
// C++ [dcl.init]p16.6.2.2
@@ -6457,6 +6486,19 @@ void InitializationSequence::InitializeFrom(Sema &S,
}
}
+ if (!S.getLangOpts().CPlusPlus &&
+ Kind.getKind() == InitializationKind::IK_Default) {
+ RecordDecl *Rec = DestType->getAsRecordDecl();
+ if (Rec && Rec->hasUninitializedExplicitInitFields()) {
+ VarDecl *Var = dyn_cast_or_null<VarDecl>(Entity.getDecl());
+ if (Var && !Initializer) {
+ S.Diag(Var->getLocation(), diag::warn_field_requires_explicit_init)
+ << /* Var-in-Record */ 1 << Rec;
+ emitUninitializedExplicitInitFields(S, Rec);
+ }
+ }
+ }
+
// - If the destination type is a reference type, see 8.5.3.
if (DestType->isReferenceType()) {
// C++0x [dcl.init.ref]p1:
@@ -7310,6 +7352,22 @@ PerformConstructorInitialization(Sema &S,
if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc))
return ExprError();
+ if (Kind.getKind() == InitializationKind::IK_Value &&
+ Constructor->isImplicit()) {
+ auto *RD = Step.Type.getCanonicalType()->getAsCXXRecordDecl();
+ if (RD && RD->isAggregate() && RD->hasUninitializedExplicitInitFields()) {
+ unsigned I = 0;
+ for (const FieldDecl *FD : RD->fields()) {
+ if (I >= ConstructorArgs.size() && FD->hasAttr<ExplicitInitAttr>()) {
+ S.Diag(Loc, diag::warn_field_requires_explicit_init)
+ << /* Var-in-Record */ 0 << FD;
+ S.Diag(FD->getLocation(), diag::note_entity_declared_at) << FD;
+ }
+ ++I;
+ }
+ }
+ }
+
TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
if (!TSInfo)
TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc);
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index ee72dd8..95abd75 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -832,6 +832,7 @@ RedeclarableResult ASTDeclReader::VisitRecordDeclImpl(RecordDecl *RD) {
RecordDeclBits.getNextBit());
RD->setHasNonTrivialToPrimitiveDestructCUnion(RecordDeclBits.getNextBit());
RD->setHasNonTrivialToPrimitiveCopyCUnion(RecordDeclBits.getNextBit());
+ RD->setHasUninitializedExplicitInitFields(RecordDeclBits.getNextBit());
RD->setParamDestroyedInCallee(RecordDeclBits.getNextBit());
RD->setArgPassingRestrictions(
(RecordArgPassingKind)RecordDeclBits.getNextBits(/*Width=*/2));
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index f8ed155..3b357f3 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -611,6 +611,7 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
RecordDeclBits.addBit(D->hasNonTrivialToPrimitiveDefaultInitializeCUnion());
RecordDeclBits.addBit(D->hasNonTrivialToPrimitiveDestructCUnion());
RecordDeclBits.addBit(D->hasNonTrivialToPrimitiveCopyCUnion());
+ RecordDeclBits.addBit(D->hasUninitializedExplicitInitFields());
RecordDeclBits.addBit(D->isParamDestroyedInCallee());
RecordDeclBits.addBits(llvm::to_underlying(D->getArgPassingRestrictions()), 2);
Record.push_back(RecordDeclBits);
@@ -2480,7 +2481,8 @@ void ASTWriter::WriteDeclAbbrevs() {
// isNonTrivialToPrimitiveCopy, isNonTrivialToPrimitiveDestroy,
// hasNonTrivialToPrimitiveDefaultInitializeCUnion,
// hasNonTrivialToPrimitiveDestructCUnion,
- // hasNonTrivialToPrimitiveCopyCUnion, isParamDestroyedInCallee,
+ // hasNonTrivialToPrimitiveCopyCUnion,
+ // hasUninitializedExplicitInitFields, isParamDestroyedInCallee,
// getArgPassingRestrictions
// ODRHash
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 26));