From 3cf538d5c49bbebac1afa6f4a5010e3d877440bb Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 11 Mar 2009 18:59:21 +0000 Subject: [PATCH] Implement basic template instantiation for fields. Reshuffle checking for FieldDecls so that the parser and the template instantiation make use of the same semantic checking module. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66685 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.def | 4 +- lib/Sema/Sema.h | 5 + lib/Sema/SemaDecl.cpp | 128 +++++++++++++------- lib/Sema/SemaDeclCXX.cpp | 3 +- lib/Sema/SemaTemplateInstantiate.cpp | 49 ++++++-- test/SemaCXX/class.cpp | 4 +- test/SemaTemplate/instantiate-field.cpp | 28 +++++ 7 files changed, 164 insertions(+), 57 deletions(-) create mode 100644 test/SemaTemplate/instantiate-field.cpp diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 2c024de380..96dc3ab283 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -253,7 +253,7 @@ DIAG(err_static_not_bitfield, ERROR, DIAG(err_typedef_not_bitfield, ERROR, "typedef member %0 cannot be a bit-field") DIAG(err_not_integral_type_bitfield, ERROR, - "bit-field %0 has non-integral type") + "bit-field %0 has non-integral type %1") DIAG(err_member_initialization, ERROR, "%0 can only be initialized if it is a static const integral data member") DIAG(err_member_function_initialization, ERROR, @@ -655,6 +655,8 @@ DIAG(note_template_class_instantiation_here, NOTE, "in instantiation of template class %0 requested here") DIAG(note_default_arg_instantiation_here, NOTE, "in instantiation of default argument for '%0' required here") +DIAG(err_field_instantiates_to_function, ERROR, + "data member instantiated with function type %0") DIAG(err_unexpected_typedef, ERROR, "unexpected type name %0: expected expression") diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 2e02004113..1a66cc0324 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -371,6 +371,11 @@ public: FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth); + FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, + RecordDecl *Record, SourceLocation Loc, + bool Mutable, Expr *BitfieldWidth, + NamedDecl *PrevDecl, + Declarator *D = 0); virtual DeclTy *ActOnIvar(Scope *S, SourceLocation DeclStart, Declarator &D, ExprTy *BitfieldWidth, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 03d00b83a3..8c82c5cad3 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3219,14 +3219,19 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, QualType FieldTy, const Expr *BitWidth) { // C99 6.7.2.1p4 - verify the field type. // C++ 9.6p3: A bit-field shall have integral or enumeration type. - if (!FieldTy->isIntegralType()) { + if (!FieldTy->isDependentType() && !FieldTy->isIntegralType()) { // Handle incomplete types with specific error. if (RequireCompleteType(FieldLoc, FieldTy, diag::err_field_incomplete)) return true; return Diag(FieldLoc, diag::err_not_integral_type_bitfield) - << FieldName << BitWidth->getSourceRange(); + << FieldName << FieldTy << BitWidth->getSourceRange(); } - + + // If the bit-width is type- or value-dependent, don't try to check + // it now. + if (BitWidth->isValueDependent() || BitWidth->isTypeDependent()) + return false; + llvm::APSInt Value; if (VerifyIntegerConstantExpression(BitWidth, &Value)) return true; @@ -3238,11 +3243,13 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, if (Value.isNegative()) return Diag(FieldLoc, diag::err_bitfield_has_negative_width) << FieldName; - uint64_t TypeSize = Context.getTypeSize(FieldTy); - // FIXME: We won't need the 0 size once we check that the field type is valid. - if (TypeSize && Value.getZExtValue() > TypeSize) - return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size) - << FieldName << (unsigned)TypeSize; + if (!FieldTy->isDependentType()) { + uint64_t TypeSize = Context.getTypeSize(FieldTy); + // FIXME: We won't need the 0 size once we check that the field type is valid. + if (TypeSize && Value.getZExtValue() > TypeSize) + return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size) + << FieldName << (unsigned)TypeSize; + } return false; } @@ -3264,11 +3271,56 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); - + QualType T = GetTypeForDeclarator(D, S); - assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); + + if (getLangOptions().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + + NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true); + if (PrevDecl && !isDeclInScope(PrevDecl, Record, S)) + PrevDecl = 0; + + FieldDecl *NewFD + = CheckFieldDecl(II, T, Record, Loc, + D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable, + BitWidth, PrevDecl, &D); + if (NewFD->isInvalidDecl() && PrevDecl) { + // Don't introduce NewFD into scope; there's already something + // with the same name in the same scope. + } else if (II) { + PushOnScopeChains(NewFD, S); + } else + Record->addDecl(NewFD); + + return NewFD; +} + +/// \brief Build a new FieldDecl and check its well-formedness. +/// +/// This routine builds a new FieldDecl given the fields name, type, +/// record, etc. \p PrevDecl should refer to any previous declaration +/// with the same name and in the same scope as the field to be +/// created. +/// +/// \returns a new FieldDecl. +/// +/// \todo The Declarator argument is a hack. It will be removed once +FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, + RecordDecl *Record, SourceLocation Loc, + bool Mutable, Expr *BitWidth, + NamedDecl *PrevDecl, + Declarator *D) { + IdentifierInfo *II = Name.getAsIdentifierInfo(); bool InvalidDecl = false; + // If we receive a broken type, recover by assuming 'int' and + // marking this declaration as invalid. + if (T.isNull()) { + InvalidDecl = true; + T = Context.IntTy; + } + // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. if (T->isVariablyModifiedType()) { @@ -3288,53 +3340,37 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, } } - if (BitWidth) { - if (VerifyBitField(Loc, II, T, BitWidth)) { - InvalidDecl = true; - DeleteExpr(BitWidth); - BitWidth = 0; - } - } else { - // Not a bitfield. - - // validate II. - + // If this is declared as a bit-field, check the bit-field. + if (BitWidth && VerifyBitField(Loc, II, T, BitWidth)) { + InvalidDecl = true; + DeleteExpr(BitWidth); + BitWidth = 0; } - FieldDecl *NewFD = FieldDecl::Create(Context, Record, - Loc, II, T, BitWidth, - D.getDeclSpec().getStorageClassSpec() == - DeclSpec::SCS_mutable); + FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, BitWidth, + Mutable); - if (II) { - NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true); - if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S) - && !isa(PrevDecl)) { - Diag(Loc, diag::err_duplicate_member) << II; - Diag(PrevDecl->getLocation(), diag::note_previous_declaration); - NewFD->setInvalidDecl(); - Record->setInvalidDecl(); - } + if (PrevDecl && !isa(PrevDecl)) { + Diag(Loc, diag::err_duplicate_member) << II; + Diag(PrevDecl->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + Record->setInvalidDecl(); } - if (getLangOptions().CPlusPlus) { - CheckExtraCXXDefaultArguments(D); - if (!T->isPODType()) - cast(Record)->setPOD(false); - } + if (getLangOptions().CPlusPlus && !T->isPODType()) + cast(Record)->setPOD(false); + + // FIXME: We need to pass in the attributes given an AST + // representation, not a parser representation. + if (D) + ProcessDeclAttributes(NewFD, *D); - ProcessDeclAttributes(NewFD, D); if (T.isObjCGCWeak()) Diag(Loc, diag::warn_attribute_weak_on_field); - if (D.getInvalidType() || InvalidDecl) + if (InvalidDecl) NewFD->setInvalidDecl(); - if (II) { - PushOnScopeChains(NewFD, S); - } else - Record->addDecl(NewFD); - return NewFD; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b708598c62..6df1600c69 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -573,7 +573,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // A function typedef ("typedef int f(); f a;"). // C++ 9.6p3: A bit-field shall have integral or enumeration type. Diag(Loc, diag::err_not_integral_type_bitfield) - << Name << BitWidth->getSourceRange(); + << Name << cast(Member)->getType() + << BitWidth->getSourceRange(); } DeleteExpr(BitWidth); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index d630e801b0..5800ab9265 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -664,7 +664,7 @@ Sema::InstantiateClassTemplateSpecialization( // instantiation. Should this be a typedef or something like it? RecordDecl *Pattern = Template->getTemplatedDecl(); - + llvm::SmallVector Fields; for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), MemberEnd = Pattern->decls_end(); Member != MemberEnd; ++Member) { @@ -690,18 +690,53 @@ Sema::InstantiateClassTemplateSpecialization( Typedef->getIdentifier(), T); ClassTemplateSpec->addDecl(New); + } + else if (FieldDecl *Field = dyn_cast(*Member)) { + // FIXME: Simplified instantiation of fields needs to be made + // "real". + QualType T = Field->getType(); + if (T->isDependentType()) { + T = InstantiateType(T, ClassTemplateSpec->getTemplateArgs(), + ClassTemplateSpec->getNumTemplateArgs(), + Field->getLocation(), + Field->getDeclName()); + if (!T.isNull() && T->isFunctionType()) { + // C++ [temp.arg.type]p3: + // If a declaration acquires a function type through a type + // dependent on a template-parameter and this causes a + // declaration that does not use the syntactic form of a + // function declarator to have function type, the program is + // ill-formed. + Diag(Field->getLocation(), diag::err_field_instantiates_to_function) + << T; + T = QualType(); + } + } + + FieldDecl *New = CheckFieldDecl(Field->getDeclName(), T, + ClassTemplateSpec, + Field->getLocation(), + Field->isMutable(), + Field->getBitWidth(), + 0); + if (New) { + ClassTemplateSpec->addDecl(New); + Fields.push_back(New); + + if (New->isInvalidDecl()) + Invalid = true; + } } } - // FIXME: Instantiate all of the members. - + // Finish checking fields. + ActOnFields(0, ClassTemplateSpec->getLocation(), ClassTemplateSpec, + &Fields[0], Fields.size(), SourceLocation(), SourceLocation(), + 0); + // Add any implicitly-declared members that we might need. AddImplicitlyDeclaredMembersToClass(ClassTemplateSpec); - // Finish the definition of this instantiation. - // FIXME: ActOnFields does more checking, which we'll eventually need. - ClassTemplateSpec->completeDefinition(Context); - // Exit the scope of this instantiation. CurContext = PreviousContext; diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp index 44ec70f07c..776fb091da 100644 --- a/test/SemaCXX/class.cpp +++ b/test/SemaCXX/class.cpp @@ -27,8 +27,8 @@ public: typedef int func(); func tm; func *ptm; - func btm : 1; // expected-error {{error: bit-field 'btm' has non-integral type}} - NestedC bc : 1; // expected-error {{error: bit-field 'bc' has non-integral type}} + func btm : 1; // expected-error {{bit-field 'btm' has non-integral type}} + NestedC bc : 1; // expected-error {{bit-field 'bc' has non-integral type}} enum E1 { en1, en2 }; diff --git a/test/SemaTemplate/instantiate-field.cpp b/test/SemaTemplate/instantiate-field.cpp new file mode 100644 index 0000000000..dbfbd47060 --- /dev/null +++ b/test/SemaTemplate/instantiate-field.cpp @@ -0,0 +1,28 @@ +// RUN: clang -fsyntax-only -verify %s + +template +struct X { + int x; + T y; // expected-error{{data member instantiated with function type}} + T* z; + T bitfield : 12; // expected-error{{bit-field 'bitfield' has non-integral type 'float'}} \ + // expected-error{{data member instantiated with function type}} + + mutable T x2; // expected-error{{data member instantiated with function type}} +}; + +void test1(const X *xi) { + int i1 = xi->x; + const int &i2 = xi->y; + int* ip1 = xi->z; + int i3 = xi->bitfield; + xi->x2 = 17; +} + +void test2(const X *xf) { + (void)xf->x; // expected-note{{in instantiation of template class 'struct X' requested here}} +} + +void test3(const X *xf) { + (void)xf->x; // expected-note{{in instantiation of template class 'struct X' requested here}} +} -- 2.40.0