Variable declaration/definition

Hi,

I'm trying to clean up variable definition code. I've given VarDecl a
new method, isThisDeclarationADefinition(), and have implemented it thus:

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.
  // FIXME: Exact C rules?
  if (isStaticDataMember()) {
    if (isOutOfLine() && (hasInit() ||
          getTemplateSpecializationKind() != TSK_ExplicitSpecialization))
      return Definition;
    else
      return DeclarationOnly;
  }
  if (hasInit())
    return Definition;
  // AST for 'extern "C" int foo;' is annotated with 'extern'.
  if (hasExternalStorage())
    return DeclarationOnly;

  // Now, in C++, everything left is a definition, but in C, if this
variable
  // is global, it is a tentative definition.
  // FIXME: It's not a tentative definition if there's a known definite
  // definition.
  if (!getASTContext().getLang().CPlusPlus && isFileVarDecl())
    return TentativeDefinition;

  return Definition;
}

Are these semantics correct for C? Can I have a standard quote? Are
global variables marked with __thread ever tentative definitions?
The current isTentativeDefinition() will return false if there is a
definite definition elsewhere in the file; I will fix this in my
implementation. Any other problems?

Sebastian

Hi,

I’m trying to clean up variable definition code. I’ve given VarDecl a
new method, isThisDeclarationADefinition(), and have implemented it thus:

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.
// FIXME: Exact C rules?
if (isStaticDataMember()) {
if (isOutOfLine() && (hasInit() ||
getTemplateSpecializationKind() != TSK_ExplicitSpecialization))
return Definition;
else
return DeclarationOnly;
}
if (hasInit())
return Definition;
// AST for ‘extern “C” int foo;’ is annotated with ‘extern’.
if (hasExternalStorage())
return DeclarationOnly;

// Now, in C++, everything left is a definition, but in C, if this
variable
// is global, it is a tentative definition.
// FIXME: It’s not a tentative definition if there’s a known definite
// definition.
if (!getASTContext().getLang().CPlusPlus && isFileVarDecl())
return TentativeDefinition;

return Definition;
}

Are these semantics correct for C?

They look correct to me, although (as you say below) you should double-check the tentative-definition semantics against isTentativeDefinition.

Can I have a standard quote?

C99 6.9.2 sayeth:

1 If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.
2 A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition.

Are
global variables marked with __thread ever tentative definitions?

I think they can be… they would just get a definition of 0 in each thread.

The current isTentativeDefinition() will return false if there is a
definite definition elsewhere in the file; I will fix this in my
implementation. Any other problems?

I don’t see any other issues. Thanks for working on this!

  • Doug