[cfe-commits] r94968 - in /cfe/trunk: include/clang/AST/Decl.h lib/AST/Decl.cpp lib/Frontend/PCHReader.cpp lib/Frontend/PCHWriter.cpp lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp
Sebastian Redl
sebastian.redl at getdesigned.at
Sun Jan 31 14:27:38 PST 2010
Author: cornedbee
Date: Sun Jan 31 16:27:38 2010
New Revision: 94968
URL: http://llvm.org/viewvc/llvm-project?rev=94968&view=rev
Log:
Add VarDecl::isThisDeclarationADefinition(), which properly encapsulates the logic for when a variable declaration is a (possibly tentativ) definition. Add a few functions building on this, and shift C tentative definition handling over to this new functionality. This shift also kills the Sema::TentativeDefinitions map and instead simply stores all declarations in the renamed list. The correct handling for multiple tentative definitions is instead shifted to the final walk of the list.
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/Frontend/PCHReader.cpp
cfe/trunk/lib/Frontend/PCHWriter.cpp
cfe/trunk/lib/Sema/Sema.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=94968&r1=94967&r2=94968&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Sun Jan 31 16:27:38 2010
@@ -538,6 +538,7 @@
/// };
/// \endcode
bool isStaticDataMember() const {
+ // If it wasn't static, it would be a FieldDecl.
return getDeclContext()->isRecord();
}
@@ -546,6 +547,26 @@
return const_cast<VarDecl*>(this)->getCanonicalDecl();
}
+ enum DefinitionKind {
+ DeclarationOnly, ///< This declaration is only a declaration.
+ TentativeDefinition, ///< This declaration is a tentative definition.
+ Definition ///< This declaration is definitely a definition.
+ };
+
+ /// \brief Check whether this declaration is a definition. If this could be
+ /// a tentative definition (in C), don't check whether there's an overriding
+ /// definition.
+ DefinitionKind isThisDeclarationADefinition() const;
+
+ /// \brief Get the tentative definition that acts as the real definition in
+ /// a TU. Returns null if there is a proper definition available.
+ const VarDecl *getActingDefinition() const;
+ VarDecl *getActingDefinition();
+
+ /// \brief Determine whether this is a tentative definition of a
+ /// variable in C.
+ bool isTentativeDefinitionNow() const;
+
/// \brief Retrieve the definition of this variable, which may come
/// from a previous declaration. Def will be set to the VarDecl that
/// contains the initializer, and the result will be that
@@ -579,10 +600,9 @@
return false;
}
- /// \brief Determine whether this is a tentative definition of a
- /// variable in C.
- bool isTentativeDefinition(ASTContext &Context) const;
-
+ bool hasInit() const {
+ return !Init.isNull();
+ }
const Expr *getInit() const {
if (Init.isNull())
return 0;
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=94968&r1=94967&r2=94968&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Sun Jan 31 16:27:38 2010
@@ -480,6 +480,82 @@
return getFirstDeclaration();
}
+VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const {
+ // C++ [basic.def]p2:
+ // A declaration is a definition unless [...] it contains the 'extern'
+ // specifier or a linkage-specification and neither an initializer [...],
+ // it declares a static data member in a class declaration [...].
+ // C++ [temp.expl.spec]p15:
+ // An explicit specialization of a static data member of a template is a
+ // definition if the declaration includes an initializer; otherwise, it is
+ // a declaration.
+ if (isStaticDataMember()) {
+ if (isOutOfLine() && (hasInit() ||
+ getTemplateSpecializationKind() != TSK_ExplicitSpecialization))
+ return Definition;
+ else
+ return DeclarationOnly;
+ }
+ // C99 6.7p5:
+ // A definition of an identifier is a declaration for that identifier that
+ // [...] causes storage to be reserved for that object.
+ // Note: that applies for all non-file-scope objects.
+ // C99 6.9.2p1:
+ // If the declaration of an identifier for an object has file scope and an
+ // initializer, the declaration is an external definition for the identifier
+ if (hasInit())
+ return Definition;
+ // AST for 'extern "C" int foo;' is annotated with 'extern'.
+ if (hasExternalStorage())
+ return DeclarationOnly;
+
+ // C99 6.9.2p2:
+ // A declaration of an object that has file scope without an initializer,
+ // and without a storage class specifier or the scs 'static', constitutes
+ // a tentative definition.
+ // No such thing in C++.
+ if (!getASTContext().getLangOptions().CPlusPlus && isFileVarDecl())
+ return TentativeDefinition;
+
+ // What's left is (in C, block-scope) declarations without initializers or
+ // external storage. These are definitions.
+ return Definition;
+}
+
+const VarDecl *VarDecl::getActingDefinition() const {
+ return const_cast<VarDecl*>(this)->getActingDefinition();
+}
+
+VarDecl *VarDecl::getActingDefinition() {
+ DefinitionKind Kind = isThisDeclarationADefinition();
+ if (Kind != TentativeDefinition)
+ return 0;
+
+ VarDecl *LastTentative = false;
+ VarDecl *First = getFirstDeclaration();
+ for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
+ I != E; ++I) {
+ Kind = (*I)->isThisDeclarationADefinition();
+ if (Kind == Definition)
+ return 0;
+ else if (Kind == TentativeDefinition)
+ LastTentative = *I;
+ }
+ return LastTentative;
+}
+
+bool VarDecl::isTentativeDefinitionNow() const {
+ DefinitionKind Kind = isThisDeclarationADefinition();
+ if (Kind != TentativeDefinition)
+ return false;
+
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ if ((*I)->isThisDeclarationADefinition() == Definition)
+ return false;
+ }
+ return true;
+}
+
const Expr *VarDecl::getDefinition(const VarDecl *&Def) const {
redecl_iterator I = redecls_begin(), E = redecls_end();
while (I != E && !I->getInit())
@@ -521,15 +597,6 @@
return 0;
}
-bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
- if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
- return false;
-
- const VarDecl *Def = 0;
- return (!getDefinition(Def) &&
- (getStorageClass() == None || getStorageClass() == Static));
-}
-
void VarDecl::setInit(ASTContext &C, Expr *I) {
if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) {
Eval->~EvaluatedStmt();
@@ -547,8 +614,7 @@
}
TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
- if (MemberSpecializationInfo *MSI
- = getASTContext().getInstantiatedFromStaticDataMember(this))
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return MSI->getTemplateSpecializationKind();
return TSK_Undeclared;
Modified: cfe/trunk/lib/Frontend/PCHReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReader.cpp?rev=94968&r1=94967&r2=94968&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReader.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReader.cpp Sun Jan 31 16:27:38 2010
@@ -2464,11 +2464,10 @@
PreloadedDecls.clear();
// If there were any tentative definitions, deserialize them and add
- // them to Sema's table of tentative definitions.
+ // them to Sema's list of tentative definitions.
for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I]));
- SemaObj->TentativeDefinitions[Var->getDeclName()] = Var;
- SemaObj->TentativeDefinitionList.push_back(Var->getDeclName());
+ SemaObj->TentativeDefinitions.push_back(Var);
}
// If there were any locally-scoped external declarations,
Modified: cfe/trunk/lib/Frontend/PCHWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriter.cpp?rev=94968&r1=94967&r2=94968&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriter.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriter.cpp Sun Jan 31 16:27:38 2010
@@ -1960,13 +1960,11 @@
}
// Build a record containing all of the tentative definitions in this file, in
- // TentativeDefinitionList order. Generally, this record will be empty for
+ // TentativeDefinitions order. Generally, this record will be empty for
// headers.
RecordData TentativeDefinitions;
- for (unsigned i = 0, e = SemaRef.TentativeDefinitionList.size(); i != e; ++i){
- VarDecl *VD =
- SemaRef.TentativeDefinitions.lookup(SemaRef.TentativeDefinitionList[i]);
- if (VD) AddDeclRef(VD, TentativeDefinitions);
+ for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) {
+ AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions);
}
// Build a record containing all of the locally-scoped external
Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=94968&r1=94967&r2=94968&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Sun Jan 31 16:27:38 2010
@@ -15,6 +15,7 @@
#include "Sema.h"
#include "TargetAttributesSema.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/APFloat.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -472,12 +473,14 @@
// translation unit contains a file scope declaration of that
// identifier, with the composite type as of the end of the
// translation unit, with an initializer equal to 0.
- for (unsigned i = 0, e = TentativeDefinitionList.size(); i != e; ++i) {
- VarDecl *VD = TentativeDefinitions.lookup(TentativeDefinitionList[i]);
-
- // If the tentative definition was completed, it will be in the list, but
- // not the map.
- if (VD == 0 || VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
+ llvm::SmallSet<VarDecl *, 32> Seen;
+ for (unsigned i = 0, e = TentativeDefinitions.size(); i != e; ++i) {
+ VarDecl *VD = TentativeDefinitions[i]->getActingDefinition();
+
+ // If the tentative definition was completed, getActingDefinition() returns
+ // null. If we've already seen this variable before, insert()'s second
+ // return value is false.
+ if (VD == 0 || VD->isInvalidDecl() || !Seen.insert(VD))
continue;
if (const IncompleteArrayType *ArrayT
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=94968&r1=94967&r2=94968&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sun Jan 31 16:27:38 2010
@@ -272,14 +272,8 @@
/// not visible.
llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls;
- /// \brief The set of tentative declarations seen so far in this
- /// translation unit for which no definition has been seen.
- ///
- /// The tentative declarations are indexed by the name of the
- /// declaration, and only the most recent tentative declaration for
- /// a given variable will be recorded here.
- llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions;
- std::vector<DeclarationName> TentativeDefinitionList;
+ /// \brief All the tentative definitions encountered in the TU.
+ std::vector<VarDecl *> TentativeDefinitions;
struct DelayedDiagnostic {
enum DDKind { Deprecation, Access };
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=94968&r1=94967&r2=94968&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Jan 31 16:27:38 2010
@@ -3570,14 +3570,6 @@
// Attach the initializer to the decl.
VDecl->setInit(Context, Init);
- // If the previous declaration of VDecl was a tentative definition,
- // remove it from the set of tentative definitions.
- if (VDecl->getPreviousDeclaration() &&
- VDecl->getPreviousDeclaration()->isTentativeDefinition(Context)) {
- bool Deleted = TentativeDefinitions.erase(VDecl->getDeclName());
- assert(Deleted && "Unrecorded tentative definition?"); Deleted=Deleted;
- }
-
if (getLangOptions().CPlusPlus) {
// Make sure we mark the destructor as used if necessary.
QualType InitType = VDecl->getType();
@@ -3602,20 +3594,8 @@
QualType Type = Var->getType();
// Record tentative definitions.
- if (Var->isTentativeDefinition(Context)) {
- std::pair<llvm::DenseMap<DeclarationName, VarDecl *>::iterator, bool>
- InsertPair =
- TentativeDefinitions.insert(std::make_pair(Var->getDeclName(), Var));
-
- // Keep the latest definition in the map. If we see 'int i; int i;' we
- // want the second one in the map.
- InsertPair.first->second = Var;
-
- // However, for the list, we don't care about the order, just make sure
- // that there are no dupes for a given declaration name.
- if (InsertPair.second)
- TentativeDefinitionList.push_back(Var->getDeclName());
- }
+ if (Var->isTentativeDefinitionNow())
+ TentativeDefinitions.push_back(Var);
// C++ [dcl.init.ref]p3:
// The initializer can be omitted for a reference only in a
@@ -3794,7 +3774,8 @@
// storage-class specifier or with the storage-class specifier "static",
// constitutes a tentative definition. Note: A tentative definition with
// external linkage is valid (C99 6.2.2p5).
- if (IDecl->isTentativeDefinition(Context) && !IDecl->isInvalidDecl()) {
+ if (IDecl->isThisDeclarationADefinition() == VarDecl::TentativeDefinition &&
+ !IDecl->isInvalidDecl()) {
if (const IncompleteArrayType *ArrayT
= Context.getAsIncompleteArrayType(T)) {
if (RequireCompleteType(IDecl->getLocation(),
More information about the cfe-commits
mailing list