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,
/// 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)
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
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; }
};
};
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; }
/// 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
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,
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) {
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,
// 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());
/// 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();
}
//===----------------------------------------------------------------------===//
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;
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;
}
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,
/// 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,
"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;
DeclContext *LexicalContext = CurContext;
ScopedDecl *PrevDecl = 0;
+ bool Invalid = false;
+
if (Name && SS.isNotEmpty()) {
// We have a nested-name tag ('struct foo::bar').
// 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.
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.
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.
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) {
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;
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.
++Found;
Diag((*Found)->getLocation(), diag::note_ambiguous_member_found);
+
return true;
}
// 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 };
}
}
-void N::f1::foo(int) { }
+void N::f1::foo(int i) {
+ f1::member = i;
+ f1::type &ir = i;
+}
namespace N {
float& f1(int x) {
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);
+}