diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 8 | ||||
-rw-r--r-- | include/clang/AST/Decl.h | 21 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 17 | ||||
-rw-r--r-- | include/clang/Basic/SourceLocation.h | 21 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 2 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 5 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 28 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 36 | ||||
-rw-r--r-- | lib/AST/TypeSerialization.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 70 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 1 | ||||
-rw-r--r-- | test/Sema/enum.c | 1 | ||||
-rw-r--r-- | test/SemaCXX/qualified-id-lookup.cpp | 18 |
14 files changed, 125 insertions, 108 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index ec48971aeb..7707b1d215 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -543,14 +543,6 @@ private: void InitBuiltinTypes(); void InitBuiltinType(QualType &R, BuiltinType::Kind K); - /// setTagDefinition - Used by RecordDecl::completeDefinition and - /// EnumDecl::completeDefinition to inform - /// about which RecordDecl/EnumDecl serves as the definition of a particular - /// struct/union/class/enum. - void setTagDefinition(TagDecl* R); - friend class EnumDecl; - friend class RecordDecl; - // Return the ObjC type encoding for a given type. void getObjCEncodingForTypeImpl(QualType t, std::string &S, bool ExpandPointedToStructures, diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index f8e5092536..c0325bdafb 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -887,6 +887,9 @@ class TypeDecl : public ScopedDecl { /// ASTContext::getTagDeclType, and ASTContext::getTemplateTypeParmType. Type *TypeForDecl; friend class ASTContext; + friend class DeclContext; + friend class TagDecl; + protected: TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, ScopedDecl *PrevDecl) @@ -965,6 +968,16 @@ public: return IsDefinition; } + /// @brief Starts the definition of this tag declaration. + /// + /// This method should be invoked at the beginning of the definition + /// of this tag declaration. It will set the tag type into a state + /// where it is in the process of being defined. + void startDefinition(); + + /// @brief Completes the definition of this tag declaration. + void completeDefinition(); + /// getDefinition - Returns the TagDecl that actually defines this /// struct/union/class/enum. When determining whether or not a /// struct/union/class/enum is completely defined, one should use this method @@ -998,6 +1011,14 @@ public: return D->getKind() >= TagFirst && D->getKind() <= TagLast; } static bool classof(const TagDecl *D) { return true; } + + static DeclContext *castToDeclContext(const TagDecl *D) { + return static_cast<DeclContext *>(const_cast<TagDecl*>(D)); + } + static TagDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<TagDecl *>(const_cast<DeclContext*>(DC)); + } + protected: void setDefinition(bool V) { IsDefinition = V; } }; diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index afcd1edd80..a74ac95324 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1194,19 +1194,30 @@ protected: }; class TagType : public Type { - TagDecl *decl; + /// Stores the TagDecl associated with this type. The decl will + /// point to the TagDecl that actually defines the entity (or is a + /// definition in progress), if there is such a definition. The + /// single-bit value will be non-zero when this tag is in the + /// process of being defined. + llvm::PointerIntPair<TagDecl *, 1> decl; friend class ASTContext; + friend class TagDecl; protected: // FIXME: We'll need the user to pass in information about whether // this type is dependent or not, because we don't have enough // information to compute it here. TagType(TagDecl *D, QualType can) - : Type(Tagged, can, /*Dependent=*/false), decl(D) {} + : Type(Tagged, can, /*Dependent=*/false), decl(D, 0) {} public: - TagDecl *getDecl() const { return decl; } + TagDecl *getDecl() const { return decl.getPointer(); } + /// @brief Determines whether this type is in the process of being + /// defined. + bool isBeingDefined() const { return decl.getInt(); } + void setBeingDefined(bool Def) { decl.setInt(Def? 1 : 0); } + virtual void getAsStringInternal(std::string &InnerString) const; static bool classof(const Type *T) { return T->getTypeClass() == Tagged; } diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h index da7ea25a54..ba359bddae 100644 --- a/include/clang/Basic/SourceLocation.h +++ b/include/clang/Basic/SourceLocation.h @@ -253,17 +253,20 @@ public: /// Prints information about this FullSourceLoc to stderr. Useful for /// debugging. void dump() const; -}; -inline bool operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { - return LHS.getRawEncoding() == RHS.getRawEncoding() && - &LHS.getManager() == &RHS.getManager(); -} + friend inline bool + operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { + return LHS.getRawEncoding() == RHS.getRawEncoding() && + LHS.SrcMgr == RHS.SrcMgr; + } -inline bool operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { - return !(LHS == RHS); -} - + friend inline bool + operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { + return !(LHS == RHS); + } + +}; + } // end namespace clang #endif diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index d0891bb350..f78f4f38d1 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -310,7 +310,7 @@ public: TK_Declaration, // Fwd decl of a tag: 'struct foo;' TK_Definition // Definition of a tag: 'struct foo { int X; } Y;' }; - virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK, + virtual DeclTy *ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 8e7410c47c..7cb035b868 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1076,11 +1076,6 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { return QualType(Decl->TypeForDecl, 0); } -void ASTContext::setTagDefinition(TagDecl* D) { - assert (D->isDefinition()); - cast<TagType>(D->TypeForDecl)->decl = D; -} - /// getTypedefType - Return the unique reference to the type for the /// specified typename decl. QualType ASTContext::getTypedefType(TypedefDecl *Decl) { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 0bc0043ccb..8ae9311017 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -144,13 +144,8 @@ void EnumDecl::Destroy(ASTContext& C) { void EnumDecl::completeDefinition(ASTContext &C, QualType NewType) { assert(!isDefinition() && "Cannot redefine enums!"); - setDefinition(true); - IntegerType = NewType; - - // Let ASTContext know that this is the defining EnumDecl for this - // type. - C.setTagDefinition(this); + TagDecl::completeDefinition(); } FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, @@ -311,6 +306,20 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { // TagDecl Implementation //===----------------------------------------------------------------------===// +void TagDecl::startDefinition() { + cast<TagType>(TypeForDecl)->decl.setPointer(this); + cast<TagType>(TypeForDecl)->decl.setInt(1); +} + +void TagDecl::completeDefinition() { + assert((!TypeForDecl || + cast<TagType>(TypeForDecl)->decl.getPointer() == this) && + "Attempt to redefine a tag definition?"); + IsDefinition = true; + cast<TagType>(TypeForDecl)->decl.setPointer(this); + cast<TagType>(TypeForDecl)->decl.setInt(0); +} + TagDecl* TagDecl::getDefinition(ASTContext& C) const { QualType T = C.getTypeDeclType(const_cast<TagDecl*>(this)); TagDecl* D = cast<TagDecl>(cast<TagType>(T)->getDecl()); @@ -351,12 +360,7 @@ void RecordDecl::Destroy(ASTContext& C) { /// complete. void RecordDecl::completeDefinition(ASTContext& C) { assert(!isDefinition() && "Cannot redefine record!"); - - setDefinition(true); - - // Let ASTContext know that this is the defining RecordDecl for this - // type. - C.setTagDefinition(this); + TagDecl::completeDefinition(); } //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 860a65a1e3..28656873ab 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -442,37 +442,15 @@ DeclContext *DeclContext::getPrimaryContext() { return static_cast<NamespaceDecl*>(this)->getOriginalNamespace(); case Decl::Enum: -#if 0 - // FIXME: See the comment for CXXRecord, below. - // The declaration associated with the enumeration type is our - // primary context. - return Context.getTypeDeclType(static_cast<EnumDecl*>(this)) - ->getAsEnumType()->getDecl(); -#else - return this; -#endif - case Decl::Record: - case Decl::CXXRecord: { - // The declaration associated with the type is be our primary - // context. -#if 0 - // FIXME: This is what we expect to do. However, it doesn't work - // because ASTContext::setTagDefinition changes the result of - // Context.getTypeDeclType, meaning that our "primary" declaration - // of a RecordDecl/CXXRecordDecl will change, and we won't be able - // to find any values inserted into the earlier "primary" - // declaration. We need better tracking of redeclarations and - // definitions. - QualType Type = Context.getTypeDeclType(static_cast<RecordDecl*>(this)); - return Type->getAsRecordType()->getDecl(); -#else - // FIXME: This hack will work for now, because the declaration we - // create when we're defining the record is the one we'll use as - // the definition later. + case Decl::CXXRecord: + // If this is a tag type that has a definition or is currently + // being defined, that definition is our primary context. + if (TagType *TagT = cast_or_null<TagType>(cast<TagDecl>(this)->TypeForDecl)) + if (TagT->isBeingDefined() || + (TagT->getDecl() && TagT->getDecl()->isDefinition())) + return TagT->getDecl(); return this; -#endif - } case Decl::ObjCMethod: return this; diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp index 42569da400..4f3eeca28c 100644 --- a/lib/AST/TypeSerialization.cpp +++ b/lib/AST/TypeSerialization.cpp @@ -258,7 +258,8 @@ Type* TagType::CreateImpl(ASTContext& Context, Deserializer& D) { Types.push_back(T); // Deserialize the decl. - T->decl = cast<TagDecl>(D.ReadOwnedPtr<Decl>(Context)); + T->decl.setPointer(cast<TagDecl>(D.ReadOwnedPtr<Decl>(Context))); + T->decl.setInt(0); return T; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index be9da6bd80..72de7107c8 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -319,7 +319,7 @@ public: virtual DeclTy *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, RecordDecl *Record); - virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK, + virtual DeclTy *ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index cfd33f6123..7346526265 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2813,9 +2813,9 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, /// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. -/// TagType indicates what kind of tag this is. TK indicates whether this is a +/// TagSpec indicates what kind of tag this is. TK indicates whether this is a /// reference/declaration/definition of a tag. -Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, +Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, @@ -2825,7 +2825,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, "Nameless record must be a definition!"); TagDecl::TagKind Kind; - switch (TagType) { + switch (TagSpec) { default: assert(0 && "Unknown tag type!"); case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break; case DeclSpec::TST_union: Kind = TagDecl::TK_union; break; @@ -2838,6 +2838,8 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, DeclContext *LexicalContext = CurContext; ScopedDecl *PrevDecl = 0; + bool Invalid = false; + if (Name && SS.isNotEmpty()) { // We have a nested-name tag ('struct foo::bar'). @@ -2898,6 +2900,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, // Recover by making this an anonymous redefinition. Name = 0; PrevDecl = 0; + Invalid = true; } else { // If this is a use, just return the declaration we found. @@ -2913,15 +2916,29 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) { Diag(NameLoc, diag::err_redefinition) << Name; Diag(Def->getLocation(), diag::note_previous_definition); - // If this is a redefinition, recover by making this struct be - // anonymous, which will make any later references get the previous - // definition. + // If this is a redefinition, recover by making this + // struct be anonymous, which will make any later + // references get the previous definition. Name = 0; PrevDecl = 0; + Invalid = true; + } else { + // If the type is currently being defined, complain + // about a nested redefinition. + TagType *Tag = cast<TagType>(Context.getTagDeclType(PrevTagDecl)); + if (Tag->isBeingDefined()) { + Diag(NameLoc, diag::err_nested_redefinition) << Name; + Diag(PrevTagDecl->getLocation(), + diag::note_previous_definition); + Name = 0; + PrevDecl = 0; + Invalid = true; + } } + // Okay, this is definition of a previously declared or referenced // tag PrevDecl. We're going to create a new Decl for it. - } + } } // If we get here we have (another) forward declaration or we // have a definition. Just create a new decl. @@ -2944,6 +2961,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, Diag(PrevDecl->getLocation(), diag::note_previous_definition); Name = 0; PrevDecl = 0; + Invalid = true; } else { // The existing declaration isn't relevant to us; we're in a // new scope, so clear out the previous declaration. @@ -3034,16 +3052,23 @@ CreateNewDecl: New->addAttr(new PackedAttr(Alignment * 8)); } + if (Invalid) + New->setInvalidDecl(); + if (Attr) ProcessDeclAttributeList(New, Attr); - // If we're declaring or defining + // If we're declaring or defining a tag in function prototype scope + // in C, note that this type can only be used within the function. if (Name && S->isFunctionPrototypeScope() && !getLangOptions().CPlusPlus) Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New); // Set the lexical context. If the tag has a C++ scope specifier, the // lexical context will be different from the semantic context. New->setLexicalDeclContext(LexicalContext); + + if (TK == TK_Definition) + New->startDefinition(); // If this has an identifier, add it to the scope stack. if (Name) { @@ -3332,22 +3357,6 @@ void Sema::ActOnFields(Scope* S, assert(EnclosingDecl && "missing record or interface decl"); RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl); - if (Record) { - QualType RecordType = Context.getTypeDeclType(Record); - if (RecordType->getAsRecordType()->getDecl()->isDefinition()) { - RecordDecl *Def = RecordType->getAsRecordType()->getDecl(); - // Diagnose code like: - // struct S { struct S {} X; }; - // We discover this when we complete the outer S. Reject and ignore the - // outer S. - Diag(Def->getLocation(), diag::err_nested_redefinition) - << Def->getDeclName(); - Diag(RecLoc, diag::note_previous_definition); - Record->setInvalidDecl(); - return; - } - } - // Verify that all the fields are okay. unsigned NumNamedMembers = 0; llvm::SmallVector<FieldDecl*, 32> RecFields; @@ -3564,19 +3573,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, EnumDecl *Enum = cast<EnumDecl>(static_cast<Decl*>(EnumDeclX)); QualType EnumType = Context.getTypeDeclType(Enum); - if (EnumType->getAsEnumType()->getDecl()->isDefinition()) { - EnumDecl *Def = EnumType->getAsEnumType()->getDecl(); - // Diagnose code like: - // enum e0 { - // E0 = sizeof(enum e0 { E1 }) - // }; - Diag(Def->getLocation(), diag::err_nested_redefinition) - << Enum->getDeclName(); - Diag(Enum->getLocation(), diag::note_previous_definition); - Enum->setInvalidDecl(); - return; - } - // TODO: If the result value doesn't fit in an int, it must be a long or long // long value. ISO C does not support this, but GCC does as an extension, // emit a warning. diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index a16c28b9dc..561ed205e8 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -625,6 +625,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name, ++Found; Diag((*Found)->getLocation(), diag::note_ambiguous_member_found); + return true; } diff --git a/test/Sema/enum.c b/test/Sema/enum.c index 4c24b580d8..b42036dc02 100644 --- a/test/Sema/enum.c +++ b/test/Sema/enum.c @@ -1,5 +1,4 @@ // RUN: clang %s -fsyntax-only -verify -pedantic - enum e {A, B = 42LL << 32, // expected-warning {{ISO C restricts enumerator values to range of 'int'}} C = -4, D = 12456 }; diff --git a/test/SemaCXX/qualified-id-lookup.cpp b/test/SemaCXX/qualified-id-lookup.cpp index 34c06140d8..cf86971f35 100644 --- a/test/SemaCXX/qualified-id-lookup.cpp +++ b/test/SemaCXX/qualified-id-lookup.cpp @@ -44,7 +44,10 @@ namespace N { } } -void N::f1::foo(int) { } +void N::f1::foo(int i) { + f1::member = i; + f1::type &ir = i; +} namespace N { float& f1(int x) { @@ -93,4 +96,17 @@ void test_a() { a::a::a::i = 4; } +struct Undef { + typedef int type; + + Undef::type member; + + static int size = sizeof(Undef); // expected-error{{invalid application of 'sizeof' to an incomplete type 'struct Undef'}} + + int f(); +}; + +int Undef::f() { + return sizeof(Undef); +} |