diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Decl.cpp | 8 | ||||
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 39 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 58 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriterDecl.cpp | 4 |
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)); |