summaryrefslogtreecommitdiffstats
path: root/lib/AST/Decl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/Decl.cpp')
-rw-r--r--lib/AST/Decl.cpp205
1 files changed, 198 insertions, 7 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index bdc8047..572d76f 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -211,6 +211,203 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
+static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
+ assert(D->getDeclContext()->getLookupContext()->isFileContext() &&
+ "Not a name having namespace scope");
+ ASTContext &Context = D->getASTContext();
+
+ // C++ [basic.link]p3:
+ // A name having namespace scope (3.3.6) has internal linkage if it
+ // is the name of
+ // - an object, reference, function or function template that is
+ // explicitly declared static; or,
+ // (This bullet corresponds to C99 6.2.2p3.)
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ // Explicitly declared static.
+ if (Var->getStorageClass() == VarDecl::Static)
+ return NamedDecl::InternalLinkage;
+
+ // - an object or reference that is explicitly declared const
+ // and neither explicitly declared extern nor previously
+ // declared to have external linkage; or
+ // (there is no equivalent in C99)
+ if (Context.getLangOptions().CPlusPlus &&
+ Var->getType().isConstant(Context) &&
+ Var->getStorageClass() != VarDecl::Extern &&
+ Var->getStorageClass() != VarDecl::PrivateExtern) {
+ bool FoundExtern = false;
+ for (const VarDecl *PrevVar = Var->getPreviousDeclaration();
+ PrevVar && !FoundExtern;
+ PrevVar = PrevVar->getPreviousDeclaration())
+ if (PrevVar->getLinkage() == NamedDecl::ExternalLinkage)
+ FoundExtern = true;
+
+ if (!FoundExtern)
+ return NamedDecl::InternalLinkage;
+ }
+ } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
+ const FunctionDecl *Function = 0;
+ if (const FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(D))
+ Function = FunTmpl->getTemplatedDecl();
+ else
+ Function = cast<FunctionDecl>(D);
+
+ // Explicitly declared static.
+ if (Function->getStorageClass() == FunctionDecl::Static)
+ return NamedDecl::InternalLinkage;
+ } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
+ // - a data member of an anonymous union.
+ if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
+ return NamedDecl::InternalLinkage;
+ }
+
+ // C++ [basic.link]p4:
+
+ // A name having namespace scope has external linkage if it is the
+ // name of
+ //
+ // - an object or reference, unless it has internal linkage; or
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ if (!Context.getLangOptions().CPlusPlus &&
+ (Var->getStorageClass() == VarDecl::Extern ||
+ Var->getStorageClass() == VarDecl::PrivateExtern)) {
+ // C99 6.2.2p4:
+ // For an identifier declared with the storage-class specifier
+ // extern in a scope in which a prior declaration of that
+ // identifier is visible, if the prior declaration specifies
+ // internal or external linkage, the linkage of the identifier
+ // at the later declaration is the same as the linkage
+ // specified at the prior declaration. If no prior declaration
+ // is visible, or if the prior declaration specifies no
+ // linkage, then the identifier has external linkage.
+ if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) {
+ if (NamedDecl::Linkage L = PrevVar->getLinkage())
+ return L;
+ }
+ }
+
+ // C99 6.2.2p5:
+ // If the declaration of an identifier for an object has file
+ // scope and no storage-class specifier, its linkage is
+ // external.
+ return NamedDecl::ExternalLinkage;
+ }
+
+ // - a function, unless it has internal linkage; or
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ // C99 6.2.2p5:
+ // If the declaration of an identifier for a function has no
+ // storage-class specifier, its linkage is determined exactly
+ // as if it were declared with the storage-class specifier
+ // extern.
+ if (!Context.getLangOptions().CPlusPlus &&
+ (Function->getStorageClass() == FunctionDecl::Extern ||
+ Function->getStorageClass() == FunctionDecl::PrivateExtern ||
+ Function->getStorageClass() == FunctionDecl::None)) {
+ // C99 6.2.2p4:
+ // For an identifier declared with the storage-class specifier
+ // extern in a scope in which a prior declaration of that
+ // identifier is visible, if the prior declaration specifies
+ // internal or external linkage, the linkage of the identifier
+ // at the later declaration is the same as the linkage
+ // specified at the prior declaration. If no prior declaration
+ // is visible, or if the prior declaration specifies no
+ // linkage, then the identifier has external linkage.
+ if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) {
+ if (NamedDecl::Linkage L = PrevFunc->getLinkage())
+ return L;
+ }
+ }
+
+ return NamedDecl::ExternalLinkage;
+ }
+
+ // - a named class (Clause 9), or an unnamed class defined in a
+ // typedef declaration in which the class has the typedef name
+ // for linkage purposes (7.1.3); or
+ // - a named enumeration (7.2), or an unnamed enumeration
+ // defined in a typedef declaration in which the enumeration
+ // has the typedef name for linkage purposes (7.1.3); or
+ if (const TagDecl *Tag = dyn_cast<TagDecl>(D))
+ if (Tag->getDeclName() || Tag->getTypedefForAnonDecl())
+ return NamedDecl::ExternalLinkage;
+
+ // - an enumerator belonging to an enumeration with external linkage;
+ if (isa<EnumConstantDecl>(D))
+ if (cast<NamedDecl>(D->getDeclContext())->getLinkage()
+ == NamedDecl::ExternalLinkage)
+ return NamedDecl::ExternalLinkage;
+
+ // - a template, unless it is a function template that has
+ // internal linkage (Clause 14);
+ if (isa<TemplateDecl>(D))
+ return NamedDecl::ExternalLinkage;
+
+ // - a namespace (7.3), unless it is declared within an unnamed
+ // namespace.
+ if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace())
+ return NamedDecl::ExternalLinkage;
+
+ return NamedDecl::NoLinkage;
+}
+
+NamedDecl::Linkage NamedDecl::getLinkage() const {
+ // Handle linkage for namespace-scope names.
+ if (getDeclContext()->getLookupContext()->isFileContext())
+ if (Linkage L = getLinkageForNamespaceScopeDecl(this))
+ return L;
+
+ // C++ [basic.link]p5:
+ // In addition, a member function, static data member, a named
+ // class or enumeration of class scope, or an unnamed class or
+ // enumeration defined in a class-scope typedef declaration such
+ // that the class or enumeration has the typedef name for linkage
+ // purposes (7.1.3), has external linkage if the name of the class
+ // has external linkage.
+ if (getDeclContext()->isRecord() &&
+ (isa<CXXMethodDecl>(this) || isa<VarDecl>(this) ||
+ (isa<TagDecl>(this) &&
+ (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl()))) &&
+ cast<RecordDecl>(getDeclContext())->getLinkage() == ExternalLinkage)
+ return ExternalLinkage;
+
+ // C++ [basic.link]p6:
+ // The name of a function declared in block scope and the name of
+ // an object declared by a block scope extern declaration have
+ // linkage. If there is a visible declaration of an entity with
+ // linkage having the same name and type, ignoring entities
+ // declared outside the innermost enclosing namespace scope, the
+ // block scope declaration declares that same entity and receives
+ // the linkage of the previous declaration. If there is more than
+ // one such matching entity, the program is ill-formed. Otherwise,
+ // if no matching entity is found, the block scope entity receives
+ // external linkage.
+ if (getLexicalDeclContext()->isFunctionOrMethod()) {
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
+ if (Function->getPreviousDeclaration())
+ if (Linkage L = Function->getPreviousDeclaration()->getLinkage())
+ return L;
+
+ return ExternalLinkage;
+ }
+
+ if (const VarDecl *Var = dyn_cast<VarDecl>(this))
+ if (Var->getStorageClass() == VarDecl::Extern ||
+ Var->getStorageClass() == VarDecl::PrivateExtern) {
+ if (Var->getPreviousDeclaration())
+ if (Linkage L = Var->getPreviousDeclaration()->getLinkage())
+ return L;
+
+ return ExternalLinkage;
+ }
+ }
+
+ // C++ [basic.link]p6:
+ // Names not covered by these rules have no linkage.
+ return NoLinkage;
+}
+
std::string NamedDecl::getQualifiedNameAsString() const {
return getQualifiedNameAsString(getASTContext().getLangOptions());
}
@@ -300,13 +497,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
}
bool NamedDecl::hasLinkage() const {
- if (const VarDecl *VD = dyn_cast<VarDecl>(this))
- return VD->hasExternalStorage() || VD->isFileVarDecl();
-
- if (isa<FunctionDecl>(this) && !isa<CXXMethodDecl>(this))
- return true;
-
- return false;
+ return getLinkage() != NoLinkage;
}
NamedDecl *NamedDecl::getUnderlyingDecl() {
OpenPOWER on IntegriCloud