diff options
Diffstat (limited to 'lib/AST/Decl.cpp')
-rw-r--r-- | lib/AST/Decl.cpp | 205 |
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() { |