diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index d3113d11929a..6c50c7b48dfe 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -196,6 +196,26 @@ public: /// \brief Determine whether this declaration has linkage. bool hasLinkage() const; + /// \brief Describes the different kinds of linkage + /// (C++ [basic.link], C99 6.2.2) that an entity may have. + enum Linkage { + /// \brief No linkage, which means that the entity is unique and + /// can only be referred to from within its scope. + NoLinkage = 0, + + /// \brief Internal linkage, which indicates that the entity can + /// be referred to from within the translation unit (but not other + /// translation units). + InternalLinkage, + + /// \brief External linkage, which indicates that the entity can + /// be referred to from other translation units. + ExternalLinkage + }; + + /// \brief Determine what kind of linkage this entity has. + Linkage getLinkage() const; + /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for /// the underlying named decl. NamedDecl *getUnderlyingDecl(); diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index bdc804722c41..b52c7ada7f34 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/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(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().isConstQualified() && + 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(D) || isa(D)) { + const FunctionDecl *Function = 0; + if (const FunctionTemplateDecl *FunTmpl + = dyn_cast(D)) + Function = FunTmpl->getTemplatedDecl(); + else + Function = cast(D); + + // Explicitly declared static. + if (Function->getStorageClass() == FunctionDecl::Static) + return NamedDecl::InternalLinkage; + } else if (const FieldDecl *Field = dyn_cast(D)) { + // - a data member of an anonymous union. + if (cast(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(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(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(D)) + if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) + return NamedDecl::ExternalLinkage; + + // - an enumerator belonging to an enumeration with external linkage; + if (isa(D)) + if (cast(D->getDeclContext())->getLinkage() + == NamedDecl::ExternalLinkage) + return NamedDecl::ExternalLinkage; + + // - a template, unless it is a function template that has + // internal linkage (Clause 14); + if (isa(D)) + return NamedDecl::ExternalLinkage; + + // - a namespace (7.3), unless it is declared within an unnamed + // namespace. + if (isa(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(this) || isa(this) || + (isa(this) && + (getDeclName() || cast(this)->getTypedefForAnonDecl()))) && + cast(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(this)) { + if (Function->getPreviousDeclaration()) + if (Linkage L = Function->getPreviousDeclaration()->getLinkage()) + return L; + + return ExternalLinkage; + } + + if (const VarDecl *Var = dyn_cast(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(this)) - return VD->hasExternalStorage() || VD->isFileVarDecl(); - - if (isa(this) && !isa(this)) - return true; - - return false; + return getLinkage() != NoLinkage; } NamedDecl *NamedDecl::getUnderlyingDecl() { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 4efecea93512..59ff2947c14c 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2365,7 +2365,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, // Functions must have external linkage. if (FunctionDecl *Func = dyn_cast(DRE->getDecl())) { - if (Func->getStorageClass() == FunctionDecl::Static) { + if (Func->getLinkage() != NamedDecl::ExternalLinkage) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_function_not_extern) << Func << Arg->getSourceRange(); @@ -2380,7 +2380,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, } if (VarDecl *Var = dyn_cast(DRE->getDecl())) { - if (!Var->hasGlobalStorage()) { + if (Var->getLinkage() != NamedDecl::ExternalLinkage) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_object_not_extern) << Var << Arg->getSourceRange(); diff --git a/clang/test/CXX/basic/basic.link/p9.cpp b/clang/test/CXX/basic/basic.link/p9.cpp new file mode 100644 index 000000000000..ecff3eebafec --- /dev/null +++ b/clang/test/CXX/basic/basic.link/p9.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// FIXME: This test is woefully incomplete. +namespace N { } // expected-note{{here}} + +// First bullet: two names with external linkage that refer to +// different kinds of entities. +void f() { + int N(); // expected-error{{redefinition}} +} + diff --git a/clang/test/SemaCXX/nested-name-spec.cpp b/clang/test/SemaCXX/nested-name-spec.cpp index 721758f4cae0..883f039fe47c 100644 --- a/clang/test/SemaCXX/nested-name-spec.cpp +++ b/clang/test/SemaCXX/nested-name-spec.cpp @@ -87,7 +87,6 @@ void f3() { N::x = 0; // expected-error {{expected a class or namespace}} { int A; A::ax = 0; } { typedef int A; A::ax = 0; } // expected-error{{expected a class or namespace}} - { int A(); A::ax = 0; } { typedef A::C A; A::ax = 0; } // expected-error {{no member named 'ax'}} { typedef A::C A; A::cx = 0; } } diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp b/clang/test/SemaTemplate/temp_arg_nontype.cpp index bde92be93dfb..0c44651ccfee 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp @@ -151,3 +151,12 @@ namespace ns { Baz(0)> b2; // This neither. } +// PR5597 +template struct X0 { }; + +struct X1 { + static int pfunc(float); +}; +void test_X0_X1() { + X0 x01; +}