From: Richard Smith Date: Fri, 20 Sep 2013 01:15:31 +0000 (+0000) Subject: Switch the semantic DeclContext for a block-scope declaration of a function or X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a41c97a5d1912ffd184381d269fd8e5a25ee5e59;p=clang Switch the semantic DeclContext for a block-scope declaration of a function or variable from being the function to being the enclosing namespace scope (in C++) or the TU (in C). This allows us to fix a selection of related issues where we would build incorrect redeclaration chains for such declarations, and fail to notice type mismatches. Such declarations are put into a new IdentifierNamespace, IDNS_LocalExtern, which is only found when searching scopes, and not found when searching DeclContexts. Such a declaration is only made visible in its DeclContext if there are no non-LocalExtern declarations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191064 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 95812d2542..e5cc85cbac 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -873,7 +873,7 @@ public: bool isLocalVarDecl() const { if (getKind() != Decl::Var) return false; - if (const DeclContext *DC = getDeclContext()) + if (const DeclContext *DC = getLexicalDeclContext()) return DC->getRedeclContext()->isFunctionOrMethod(); return false; } @@ -883,7 +883,7 @@ public: bool isFunctionOrMethodVarDecl() const { if (getKind() != Decl::Var) return false; - const DeclContext *DC = getDeclContext()->getRedeclContext(); + const DeclContext *DC = getLexicalDeclContext()->getRedeclContext(); return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block; } @@ -959,7 +959,7 @@ public: if (K == ParmVar || K == ImplicitParam) return false; - if (getDeclContext()->getRedeclContext()->isFileContext()) + if (getLexicalDeclContext()->getRedeclContext()->isFileContext()) return true; if (isStaticDataMember()) @@ -3472,10 +3472,8 @@ void Redeclarable::setPreviousDeclaration(decl_type *PrevDecl) { // If the declaration was previously visible, a redeclaration of it remains // visible even if it wouldn't be visible by itself. - // FIXME: Once we handle local extern decls properly, this should inherit - // the visibility from MostRecent, not from PrevDecl. static_cast(this)->IdentifierNamespace |= - PrevDecl->getIdentifierNamespace() & + MostRecent->getIdentifierNamespace() & (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type); } else { // Make this first. diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 2dbfa262c4..e83ca831cf 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -159,7 +159,12 @@ public: /// This declaration is a C++ operator declared in a non-class /// context. All such operators are also in IDNS_Ordinary. /// C++ lexical operator lookup looks for these. - IDNS_NonMemberOperator = 0x0400 + IDNS_NonMemberOperator = 0x0400, + + /// This declaration is a function-local extern declaration of a + /// variable or function. This may also be IDNS_Ordinary if it + /// has been declared outside any function. + IDNS_LocalExtern = 0x0800 }; /// ObjCDeclQualifier - 'Qualifiers' written next to the return and @@ -828,6 +833,32 @@ public: /// \brief Whether this declaration is a function or function template. bool isFunctionOrFunctionTemplate() const; + /// \brief Changes the namespace of this declaration to reflect that it's + /// a function-local extern declaration. + /// + /// These declarations appear in the lexical context of the extern + /// declaration, but in the semantic context of the enclosing namespace + /// scope. + void setLocalExternDecl() { + assert((IdentifierNamespace == IDNS_Ordinary || + IdentifierNamespace == IDNS_OrdinaryFriend) && + "namespace is not ordinary"); + + Decl *Prev = getPreviousDecl(); + IdentifierNamespace &= ~IDNS_Ordinary; + + IdentifierNamespace |= IDNS_LocalExtern; + if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary) + IdentifierNamespace |= IDNS_Ordinary; + } + + /// \brief Determine whether this is a block-scope declaration with linkage. + /// This will either be a local variable declaration declared 'extern', or a + /// local function declaration. + bool isLocalExternDecl() { + return IdentifierNamespace & IDNS_LocalExtern; + } + /// \brief Changes the namespace of this declaration to reflect that it's /// the object of a friend declaration. /// @@ -838,22 +869,25 @@ public: void setObjectOfFriendDecl(bool PerformFriendInjection = false) { unsigned OldNS = IdentifierNamespace; assert((OldNS & (IDNS_Tag | IDNS_Ordinary | - IDNS_TagFriend | IDNS_OrdinaryFriend)) && + IDNS_TagFriend | IDNS_OrdinaryFriend | + IDNS_LocalExtern)) && "namespace includes neither ordinary nor tag"); assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type | - IDNS_TagFriend | IDNS_OrdinaryFriend)) && + IDNS_TagFriend | IDNS_OrdinaryFriend | + IDNS_LocalExtern)) && "namespace includes other than ordinary or tag"); Decl *Prev = getPreviousDecl(); - IdentifierNamespace = 0; + IdentifierNamespace &= ~(IDNS_Ordinary | IDNS_Tag | IDNS_Type); + if (OldNS & (IDNS_Tag | IDNS_TagFriend)) { IdentifierNamespace |= IDNS_TagFriend; - if (PerformFriendInjection || + if (PerformFriendInjection || (Prev && Prev->getIdentifierNamespace() & IDNS_Tag)) IdentifierNamespace |= IDNS_Tag | IDNS_Type; } - if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) { + if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) { IdentifierNamespace |= IDNS_OrdinaryFriend; if (PerformFriendInjection || (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)) diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h index d22b219d9b..d09510622a 100644 --- a/include/clang/Sema/Lookup.h +++ b/include/clang/Sema/Lookup.h @@ -613,6 +613,13 @@ public: return Filter(*this); } + void setFindLocalExtern(bool FindLocalExtern) { + if (FindLocalExtern) + IDNS |= Decl::IDNS_LocalExtern; + else + IDNS &= ~Decl::IDNS_LocalExtern; + } + private: void diagnose() { if (isAmbiguous()) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index d39d8d5d55..9c366190d3 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1451,6 +1451,7 @@ public: bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, SourceLocation Loc); + static bool adjustContextForLocalExternDecl(DeclContext *&DC); void DiagnoseFunctionSpecifiers(const DeclSpec &DS); void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R); void CheckShadow(Scope *S, VarDecl *D); @@ -6465,8 +6466,9 @@ public: void BuildVariableInstantiation(VarDecl *NewVar, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs, - LateInstantiatedAttrVec *LateAttrs = 0, - LocalInstantiationScope *StartingScope = 0, + LateInstantiatedAttrVec *LateAttrs, + DeclContext *Owner, + LocalInstantiationScope *StartingScope, bool InstantiatingVarTemplate = false); void InstantiateVariableInitializer( VarDecl *Var, VarDecl *OldVar, diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index bd8d3e95a8..4ecbf0ba77 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -1483,7 +1483,9 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) { DeclContext *DC = D->getDeclContext(); if (FunctionDecl *FN = dyn_cast(D)) { - if (!DC->isFunctionOrMethod()) + if (D->getLexicalDeclContext()->isFunctionOrMethod()) + DC = D->getLexicalDeclContext(); + else DC = FN; } else if (TemplateDecl *TD = dyn_cast(D)) { DC = cast(TD->getTemplatedDecl()); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 5e084eb5d4..e3e17b9601 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -715,8 +715,8 @@ unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) { return CCP_Unlikely; // Context-based decisions. - const DeclContext *DC = ND->getDeclContext()->getRedeclContext(); - if (DC->isFunctionOrMethod() || isa(DC)) { + const DeclContext *LexicalDC = ND->getLexicalDeclContext(); + if (LexicalDC->isFunctionOrMethod()) { // _cmd is relatively rare if (const ImplicitParamDecl *ImplicitParam = dyn_cast(ND)) @@ -726,6 +726,8 @@ unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) { return CCP_LocalDeclaration; } + + const DeclContext *DC = ND->getDeclContext()->getRedeclContext(); if (DC->isRecord() || isa(DC)) return CCP_MemberDeclaration; @@ -876,8 +878,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { for (; I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. if (I->first->hasTagIdentifierNamespace() && - (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | - Decl::IDNS_ObjCProtocol))) + (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | + Decl::IDNS_LocalExtern | Decl::IDNS_ObjCProtocol))) continue; // Protocols are in distinct namespaces from everything else. @@ -1038,7 +1040,9 @@ void ResultBuilder::ExitScope() { bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const { ND = cast(ND->getUnderlyingDecl()); - unsigned IDNS = Decl::IDNS_Ordinary; + // If name lookup finds a local extern declaration, then we are in a + // context where it behaves like an ordinary name. + unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern; if (SemaRef.getLangOpts().CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member; else if (SemaRef.getLangOpts().ObjC1) { @@ -1056,7 +1060,7 @@ bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const { if (isa(ND) || isa(ND)) return false; - unsigned IDNS = Decl::IDNS_Ordinary; + unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern; if (SemaRef.getLangOpts().CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member; else if (SemaRef.getLangOpts().ObjC1) { @@ -1083,7 +1087,7 @@ bool ResultBuilder::IsIntegralConstantValue(const NamedDecl *ND) const { bool ResultBuilder::IsOrdinaryNonValueName(const NamedDecl *ND) const { ND = cast(ND->getUnderlyingDecl()); - unsigned IDNS = Decl::IDNS_Ordinary; + unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern; if (SemaRef.getLangOpts().CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 4d4637fd14..68762e97fa 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1020,12 +1020,12 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { if (AddToContext) CurContext->addDecl(D); - // Out-of-line definitions shouldn't be pushed into scope in C++. - // Out-of-line variable and function definitions shouldn't even in C. - if ((getLangOpts().CPlusPlus || isa(D) || isa(D)) && - D->isOutOfLine() && + // Out-of-line definitions shouldn't be pushed into scope in C++, unless they + // are function-local declarations. + if (getLangOpts().CPlusPlus && D->isOutOfLine() && !D->getDeclContext()->getRedeclContext()->Equals( - D->getLexicalDeclContext()->getRedeclContext())) + D->getLexicalDeclContext()->getRedeclContext()) && + !D->getLexicalDeclContext()->isFunctionOrMethod()) return; // Template instantiations should also not be pushed into scope. @@ -2426,7 +2426,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S, ? New->getTypeSourceInfo()->getType()->castAs() : NewType)->getResultType(); QualType ResQT; - if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType)) { + if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) && + !((NewQType->isDependentType() || OldQType->isDependentType()) && + New->isLocalExternDecl())) { if (NewDeclaredReturnType->isObjCObjectPointerType() && OldDeclaredReturnType->isObjCObjectPointerType()) ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); @@ -2578,6 +2580,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S, if (OldQTypeForComparison == NewQType) return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld); + if ((NewQType->isDependentType() || OldQType->isDependentType()) && + New->isLocalExternDecl()) { + // It's OK if we couldn't merge types for a local function declaraton + // if either the old or new type is dependent. We'll merge the types + // when we instantiate the function. + return false; + } + // Fall through for conflicting redeclarations and redefinitions. } @@ -2710,7 +2720,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S, // local declaration will produce a hard error; if it doesn't // remain visible, a single bogus local redeclaration (which is // actually only a warning) could break all the downstream code. - if (!New->getDeclContext()->isFunctionOrMethod()) + if (!New->getLexicalDeclContext()->isFunctionOrMethod()) New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin); return false; @@ -2820,18 +2830,21 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, NewArray->getElementType())) MergedT = New->getType(); } else if (Old->getType()->isArrayType() && - New->getType()->isIncompleteArrayType()) { + New->getType()->isIncompleteArrayType()) { const ArrayType *OldArray = Context.getAsArrayType(Old->getType()); const ArrayType *NewArray = Context.getAsArrayType(New->getType()); if (Context.hasSameType(OldArray->getElementType(), NewArray->getElementType())) MergedT = Old->getType(); - } else if (New->getType()->isObjCObjectPointerType() - && Old->getType()->isObjCObjectPointerType()) { - MergedT = Context.mergeObjCGCQualifiers(New->getType(), - Old->getType()); + } else if (New->getType()->isObjCObjectPointerType() && + Old->getType()->isObjCObjectPointerType()) { + MergedT = Context.mergeObjCGCQualifiers(New->getType(), + Old->getType()); } } else { + // C 6.2.7p2: + // All declarations that refer to the same object or function shall have + // compatible type. MergedT = Context.mergeTypes(New->getType(), Old->getType()); } if (MergedT.isNull()) { @@ -4308,8 +4321,15 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, // If this has an identifier and is not an invalid redeclaration or // function template specialization, add it to the scope stack. if (New->getDeclName() && AddToScope && - !(D.isRedeclaration() && New->isInvalidDecl())) - PushOnScopeChains(New, S); + !(D.isRedeclaration() && New->isInvalidDecl())) { + // Only make a locally-scoped extern declaration visible if it is the first + // declaration of this entity. Qualified lookup for such an entity should + // only find this declaration if there is no visible declaration of it. + bool AddToContext = !D.isRedeclaration() || !New->isLocalExternDecl(); + PushOnScopeChains(New, S, AddToContext); + if (!AddToContext) + CurContext->addHiddenDecl(New); + } return New; } @@ -4808,6 +4828,30 @@ static bool shouldConsiderLinkage(const FunctionDecl *FD) { llvm_unreachable("Unexpected context"); } +/// Adjust the \c DeclContext for a function or variable that might be a +/// function-local external declaration. +bool Sema::adjustContextForLocalExternDecl(DeclContext *&DC) { + if (!DC->isFunctionOrMethod()) + return false; + + // If this is a local extern function or variable declared within a function + // template, don't add it into the enclosing namespace scope until it is + // instantiated; it might have a dependent type right now. + if (DC->isDependentContext()) + return true; + + // C++11 [basic.link]p7: + // When a block scope declaration of an entity with linkage is not found to + // refer to some other declaration, then that entity is a member of the + // innermost enclosing namespace. + // + // Per C++11 [namespace.def]p6, the innermost enclosing namespace is a + // semantically-enclosing namespace, not a lexically-enclosing one. + while (!DC->isFileContext() && !isa(DC)) + DC = DC->getParent(); + return true; +} + NamedDecl * Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, @@ -4820,6 +4864,10 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec()); + DeclContext *OriginalDC = DC; + bool IsLocalExternDecl = SC == SC_Extern && + adjustContextForLocalExternDecl(DC); + if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) { // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and // half array type (unless the cl_khr_fp16 extension is enabled). @@ -5150,6 +5198,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (NewTemplate) NewTemplate->setLexicalDeclContext(CurContext); + if (IsLocalExternDecl) + NewVD->setLocalExternDecl(); + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) { if (NewVD->hasLocalStorage()) { // C++11 [dcl.stc]p4: @@ -5277,7 +5328,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). FilterLookupForScope( - Previous, DC, S, shouldConsiderLinkage(NewVD), + Previous, OriginalDC, S, shouldConsiderLinkage(NewVD), IsExplicitSpecialization || IsVariableTemplateSpecialization); // Check whether the previous declaration is in the same block scope. This @@ -5286,7 +5337,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD->isLocalVarDecl() && NewVD->hasExternalStorage()) NewVD->setPreviousDeclInSameBlockScope( Previous.isSingleResult() && !Previous.isShadowed() && - isDeclInScope(Previous.getFoundDecl(), DC, S, false)); + isDeclInScope(Previous.getFoundDecl(), OriginalDC, S, false)); if (!getLangOpts().CPlusPlus) { D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); @@ -5543,12 +5594,8 @@ static bool checkForConflictWithNonVisibleExternC(Sema &S, const T *ND, LookupResult &Previous) { if (!S.getLangOpts().CPlusPlus) { // In C, when declaring a global variable, look for a corresponding 'extern' - // variable declared in function scope. - // - // FIXME: The corresponding case in C++ does not work. We should instead - // set the semantic DC for an extern local variable to be the innermost - // enclosing namespace, and ensure they are only found by redeclaration - // lookup. + // variable declared in function scope. We don't need this in C++, because + // we find local extern decls in the surrounding file-scope DeclContext. if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName())) { Previous.clear(); @@ -6032,6 +6079,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration( bool FDisConst = MD && MD->isConst(); bool IsMember = MD || !IsLocalFriend; + // FIXME: These notes are poorly worded for the local friend case. if (unsigned Idx = NearMatch->second) { ParmVarDecl *FDParam = FD->getParamDecl(Idx-1); SourceLocation Loc = FDParam->getTypeSpecStartLoc(); @@ -6455,6 +6503,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool isVirtualOkay = false; + DeclContext *OriginalDC = DC; + bool IsLocalExternDecl = adjustContextForLocalExternDecl(DC); + FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC, isVirtualOkay); if (!NewFD) return 0; @@ -6462,6 +6513,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer()) NewFD->setTopLevelDeclInObjCContainer(); + // Set the lexical context. If this is a function-scope declaration, or has a + // C++ scope specifier, or is the object of a friend declaration, the lexical + // context will be different from the semantic context. + NewFD->setLexicalDeclContext(CurContext); + + if (IsLocalExternDecl) + NewFD->setLocalExternDecl(); + if (getLangOpts().CPlusPlus) { bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); @@ -6489,12 +6548,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, isFunctionTemplateSpecialization = false; if (D.isInvalidType()) NewFD->setInvalidDecl(); - - // Set the lexical context. If the declarator has a C++ - // scope specifier, or is the object of a friend declaration, the - // lexical context will be different from the semantic context. - NewFD->setLexicalDeclContext(CurContext); - + // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. bool Invalid = false; @@ -6750,7 +6804,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Filter out previous declarations that don't match the scope. - FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewFD), + FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD), isExplicitSpecialization || isFunctionTemplateSpecialization); @@ -9232,21 +9286,21 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, // Don't warn for OpenCL kernels. if (FD->hasAttr()) return false; - + bool MissingPrototype = true; for (const FunctionDecl *Prev = FD->getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) { // Ignore any declarations that occur in function or method // scope, because they aren't visible from the header. - if (Prev->getDeclContext()->isFunctionOrMethod()) + if (Prev->getLexicalDeclContext()->isFunctionOrMethod()) continue; - + MissingPrototype = !Prev->getType()->isFunctionProtoType(); if (FD->getNumParams() == 0) PossibleZeroParamPrototype = Prev; break; } - + return MissingPrototype; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index dc33f2faf6..d4f9cc4380 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -438,9 +438,9 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // declaration (not even to the same value). // // C++ [dcl.fct.default]p6: - // Except for member functions of class templates, the default arguments - // in a member function definition that appears outside of the class - // definition are added to the set of default arguments provided by the + // Except for member functions of class templates, the default arguments + // in a member function definition that appears outside of the class + // definition are added to the set of default arguments provided by the // member function declaration in the class definition. for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) { ParmVarDecl *OldParam = Old->getParamDecl(p); @@ -450,9 +450,18 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, bool NewParamHasDfl = NewParam->hasDefaultArg(); NamedDecl *ND = Old; - if (S && !isDeclInScope(ND, New->getDeclContext(), S)) + + // The declaration context corresponding to the scope is the semantic + // parent, unless this is a local function declaration, in which case + // it is that surrounding function. + DeclContext *ScopeDC = New->getLexicalDeclContext(); + if (!ScopeDC->isFunctionOrMethod()) + ScopeDC = New->getDeclContext(); + if (S && !isDeclInScope(ND, ScopeDC, S) && + !New->getDeclContext()->isRecord()) // Ignore default parameters of old decl if they are not in - // the same scope. + // the same scope and this is not an out-of-line definition of + // a member function. OldParamHasDfl = false; if (OldParamHasDfl && NewParamHasDfl) { @@ -11486,6 +11495,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, // declared the function in, if we were permitted to, for error recovery. DC = FunctionContainingLocalClass; } + adjustContextForLocalExternDecl(DC); // C++ [class.friend]p6: // A function can be defined in a friend declaration of a class if and diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d68bdbb425..d036612293 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2459,7 +2459,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, // turn off ADL anyway). if (isa(D)) D = cast(D)->getTargetDecl(); - else if (D->getDeclContext()->isFunctionOrMethod()) + else if (D->getLexicalDeclContext()->isFunctionOrMethod()) return false; // C++0x [basic.lookup.argdep]p3: diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index c26960670e..a645986ac3 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -223,6 +223,8 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend; } + if (Redeclaration) + IDNS |= Decl::IDNS_LocalExtern; break; case Sema::LookupOperatorName: @@ -847,6 +849,26 @@ static std::pair findOuterContext(Scope *S) { return std::make_pair(Lexical, false); } +namespace { +/// An RAII object to specify that we want to find block scope extern +/// declarations. +struct FindLocalExternScope { + FindLocalExternScope(LookupResult &R) + : R(R), OldFindLocalExtern(R.getIdentifierNamespace() & + Decl::IDNS_LocalExtern) { + R.setFindLocalExtern(R.getIdentifierNamespace() & Decl::IDNS_Ordinary); + } + void restore() { + R.setFindLocalExtern(OldFindLocalExtern); + } + ~FindLocalExternScope() { + restore(); + } + LookupResult &R; + bool OldFindLocalExtern; +}; +} + bool Sema::CppLookupName(LookupResult &R, Scope *S) { assert(getLangOpts().CPlusPlus && "Can perform only C++ lookup"); @@ -891,6 +913,10 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { bool VisitedUsingDirectives = false; bool LeftStartingScope = false; DeclContext *OutsideOfTemplateParamDC = 0; + + // When performing a scope lookup, we want to find local extern decls. + FindLocalExternScope FindLocals(R); + for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { DeclContext *Ctx = static_cast(S->getEntity()); @@ -1046,7 +1072,12 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { UDirs.visitScopeChain(Initial, S); UDirs.done(); } - + + // If we're not performing redeclaration lookup, do not look for local + // extern declarations outside of a function scope. + if (!R.isForRedeclaration()) + FindLocals.restore(); + // Lookup namespace scope, and global scope. // Unqualified name lookup in C++ requires looking into scopes // that aren't strictly lexical, and therefore we walk through the @@ -1292,6 +1323,9 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { S = S->getParent(); } + // When performing a scope lookup, we want to find local extern decls. + FindLocalExternScope FindLocals(R); + // Scan up the scope chain looking for a decl that matches this // identifier that is in the appropriate namespace. This search // should not take long, as shadowing of names is uncommon, and @@ -1361,6 +1395,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { R.resolveKind(); } + return true; } } else { @@ -2858,7 +2893,11 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, NamedDecl *D = *I; // If the only declaration here is an ordinary friend, consider // it only if it was declared in an associated classes. - if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) { + if ((D->getIdentifierNamespace() & Decl::IDNS_Ordinary) == 0) { + // If it's neither ordinarily visible nor a friend, we can't find it. + if ((D->getIdentifierNamespace() & Decl::IDNS_OrdinaryFriend) == 0) + continue; + bool DeclaredInAssociatedClass = false; for (Decl *DI = D; DI; DI = DI->getPreviousDecl()) { DeclContext *LexDC = DI->getLexicalDeclContext(); @@ -3160,6 +3199,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, (!S->getParent() && !Visited.alreadyVisitedContext((DeclContext *)S->getEntity())) || ((DeclContext *)S->getEntity())->isFunctionOrMethod()) { + FindLocalExternScope FindLocals(Result); // Walk through the declarations in this Scope. for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); D != DEnd; ++D) { diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8cd37258b6..e03e8c55c9 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -347,8 +347,12 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, return 0; } + DeclContext *DC = Owner; + if (D->isLocalExternDecl()) + SemaRef.adjustContextForLocalExternDecl(DC); + // Build the instantiated declaration. - VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(), + VarDecl *Var = VarDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), D->getLocation(), D->getIdentifier(), DI->getType(), DI, D->getStorageClass()); @@ -361,7 +365,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, if (SubstQualifier(D, Var)) return 0; - SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, + SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner, StartingScope, InstantiatingVarTemplate); return Var; } @@ -1199,11 +1203,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } // If we're instantiating a local function declaration, put the result - // in the owner; otherwise we need to find the instantiated context. + // in the enclosing namespace; otherwise we need to find the instantiated + // context. DeclContext *DC; - if (D->getDeclContext()->isFunctionOrMethod()) + if (D->isLocalExternDecl()) { DC = Owner; - else if (isFriend && QualifierLoc) { + SemaRef.adjustContextForLocalExternDecl(DC); + } else if (isFriend && QualifierLoc) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); DC = SemaRef.computeDeclContext(SS); @@ -1227,8 +1233,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, if (QualifierLoc) Function->setQualifierInfo(QualifierLoc); + if (D->isLocalExternDecl()) + Function->setLocalExternDecl(); + DeclContext *LexicalDC = Owner; - if (!isFriend && D->isOutOfLine()) { + if (!isFriend && D->isOutOfLine() && !D->isLocalExternDecl()) { assert(D->getDeclContext()->isFileContext()); LexicalDC = D->getDeclContext(); } @@ -1294,8 +1303,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, bool isExplicitSpecialization = false; - LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(), - Sema::LookupOrdinaryName, Sema::ForRedeclaration); + LookupResult Previous( + SemaRef, Function->getDeclName(), SourceLocation(), + D->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage + : Sema::LookupOrdinaryName, + Sema::ForRedeclaration); if (DependentFunctionTemplateSpecializationInfo *Info = D->getDependentSpecializationInfo()) { @@ -1427,6 +1439,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } } + if (Function->isLocalExternDecl() && !Function->getPreviousDecl()) + DC->makeDeclVisibleInContext(PrincipalDecl); + if (Function->isOverloadedOperator() && !DC->isRecord() && PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) PrincipalDecl->setNonMemberOperator(); @@ -2358,7 +2373,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( return 0; SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, - StartingScope); + Owner, StartingScope); return Var; } @@ -2680,7 +2695,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( if (VarDecl *Def = PartialSpec->getDefinition(SemaRef.getASTContext())) PartialSpec = cast(Def); SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs, - LateAttrs, StartingScope); + LateAttrs, Owner, StartingScope); InstPartialSpec->setInit(PartialSpec->getInit()); return InstPartialSpec; @@ -3335,13 +3350,19 @@ VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( void Sema::BuildVariableInstantiation( VarDecl *NewVar, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs, - LateInstantiatedAttrVec *LateAttrs, LocalInstantiationScope *StartingScope, + LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner, + LocalInstantiationScope *StartingScope, bool InstantiatingVarTemplate) { + // If we are instantiating a local extern declaration, the + // instantiation belongs lexically to the containing function. // If we are instantiating a static data member defined // out-of-line, the instantiation will have the same lexical // context (which will be a namespace scope) as the template. - if (OldVar->isOutOfLine()) + if (OldVar->isLocalExternDecl()) { + NewVar->setLocalExternDecl(); + NewVar->setLexicalDeclContext(Owner); + } else if (OldVar->isOutOfLine()) NewVar->setLexicalDeclContext(OldVar->getLexicalDeclContext()); NewVar->setTSCSpec(OldVar->getTSCSpec()); NewVar->setInitStyle(OldVar->getInitStyle()); @@ -3374,11 +3395,13 @@ void Sema::BuildVariableInstantiation( if (NewVar->hasAttrs()) CheckAlignasUnderalignment(NewVar); - LookupResult Previous(*this, NewVar->getDeclName(), NewVar->getLocation(), - Sema::LookupOrdinaryName, Sema::ForRedeclaration); + LookupResult Previous( + *this, NewVar->getDeclName(), NewVar->getLocation(), + NewVar->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage + : Sema::LookupOrdinaryName, + Sema::ForRedeclaration); - if (NewVar->getLexicalDeclContext()->isFunctionOrMethod() && - OldVar->getPreviousDecl()) { + if (NewVar->isLocalExternDecl() && OldVar->getPreviousDecl()) { // We have a previous declaration. Use that one, so we merge with the // right type. if (NamedDecl *NewPrev = FindInstantiatedDecl( @@ -3389,13 +3412,13 @@ void Sema::BuildVariableInstantiation( LookupQualifiedName(Previous, NewVar->getDeclContext(), false); CheckVariableDeclaration(NewVar, Previous); - if (OldVar->isOutOfLine()) { - OldVar->getLexicalDeclContext()->addDecl(NewVar); - if (!InstantiatingVarTemplate) + if (!InstantiatingVarTemplate) { + NewVar->getLexicalDeclContext()->addHiddenDecl(NewVar); + if (!NewVar->isLocalExternDecl() || !NewVar->getPreviousDecl()) NewVar->getDeclContext()->makeDeclVisibleInContext(NewVar); - } else { - if (!InstantiatingVarTemplate) - NewVar->getDeclContext()->addDecl(NewVar); + } + + if (!OldVar->isOutOfLine()) { if (NewVar->getDeclContext()->isFunctionOrMethod()) CurrentInstantiationScope->InstantiatedLocal(OldVar, NewVar); } diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index a9225fc81b..0d8e05711e 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -946,7 +946,13 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { VD->VarDeclBits.ARCPseudoStrong = Record[Idx++]; VD->VarDeclBits.IsConstexpr = Record[Idx++]; VD->VarDeclBits.PreviousDeclInSameBlockScope = Record[Idx++]; - VD->setCachedLinkage(Linkage(Record[Idx++])); + Linkage VarLinkage = Linkage(Record[Idx++]); + VD->setCachedLinkage(VarLinkage); + + // Reconstruct the one piece of the IdentifierNamespace that we need. + if (VarLinkage != NoLinkage && + VD->getLexicalDeclContext()->isFunctionOrMethod()) + VD->setLocalExternDecl(); // Only true variables (not parameters or implicit parameters) can be merged. if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam) @@ -2199,8 +2205,6 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) { // // FIXME: In this case, the declaration should only be visible if a module // that makes it visible has been imported. - // FIXME: This is not correct in the case where previous is a local extern - // declaration and D is a friend declaraton. D->IdentifierNamespace |= previous->IdentifierNamespace & (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type); diff --git a/test/CXX/basic/basic.link/p7.cpp b/test/CXX/basic/basic.link/p7.cpp new file mode 100644 index 0000000000..9a85eacdda --- /dev/null +++ b/test/CXX/basic/basic.link/p7.cpp @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -verify -std=c++1y %s + +// Example from the standard. +namespace X { + void p() { + q(); // expected-error {{undeclared}} + extern void q(); + } + void middle() { + q(); // expected-error {{undeclared}} + } + void q() { /*...*/ } + void bottom() { + q(); + } +} +int q(); + +namespace Test1 { + void f() { + extern int a; // expected-note {{previous}} + int g(void); // expected-note {{previous}} + } + double a; // expected-error {{different type: 'double' vs 'int'}} + double g(); // expected-error {{differ only in their return type}} +} + +namespace Test2 { + void f() { + extern int a; // expected-note {{previous}} + int g(void); // expected-note {{previous}} + } + void h() { + extern double a; // expected-error {{different type: 'double' vs 'int'}} + double g(void); // expected-error {{differ only in their return type}} + } +} + +namespace Test3 { + constexpr void (*f())() { + void h(); + return &h; + } + constexpr void (*g())() { + void h(); + return &h; + } + static_assert(f() == g(), ""); +} + +namespace Test4 { + template + constexpr void (*f())() { + void h(); + return &h; + } + static_assert(f() == f(), ""); + void h(); + static_assert(f() == &h, ""); +} + +namespace Test5 { + constexpr auto f() -> void (*)() { + void g(); + struct X { + friend void g(); + static constexpr auto h() -> void (*)() { return g; } + }; + return X::h(); + } + void g(); + static_assert(f() == g, ""); +} diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp index 2dbc143065..e040d5b264 100644 --- a/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp @@ -61,6 +61,8 @@ namespace test6 { int x = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}} } int y = sizeof(array); + extern int array[]; + int z = sizeof(array); } } @@ -71,6 +73,19 @@ namespace test7 { int x = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}} } int y = sizeof(array); + extern int array[]; + int z = sizeof(array); +} + +namespace test8 { + extern int array[]; + void test() { + extern int array[100]; + int x = sizeof(array); + } + int y = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}} + extern int array[]; + int z = sizeof(array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}} } namespace dependent { @@ -143,10 +158,52 @@ namespace dependent { } template void n() { - extern T n_var; + extern T n_var; // expected-error {{redefinition of 'n_var' with a different type: 'double' vs 'int'}} expected-note {{previous}} + extern T n_fn(); // expected-error {{functions that differ only in their return type cannot be overloaded}} expected-note {{previous}} } template void n(); - // FIXME: Diagnose this! - float n_var; - template void n(); + template void n(); // expected-note {{in instantiation of}} + + template void o() { + extern T o_var; // expected-note {{previous}} + extern T o_fn(); // expected-note {{previous}} + } + template void o(); + float o_var; // expected-error {{redefinition of 'o_var' with a different type: 'float' vs 'int'}} + float o_fn(); // expected-error {{functions that differ only in their return type cannot be overloaded}} + + int p_var; + int p_fn(); + template void p() { + extern T p_var; + extern T p_fn(); + } +} + +namespace use_outside_ns { + namespace A { + extern int a[3]; + extern int b[]; + extern int c[3]; + void f() { + extern int a[]; + extern int b[3]; + } + template void x() { + extern T c; + extern T d; + } + extern int d[3]; + template void x(); + } + int w = sizeof(A::a); + int x = sizeof(A::b); // expected-error {{incomplete}} + int y = sizeof(A::c); + int z = sizeof(A::d); + namespace A { + int g() { return sizeof(a); } + int h() { return sizeof(b); } // expected-error {{incomplete}} + int i() { return sizeof(c); } + int j() { return sizeof(d); } + } } diff --git a/test/CXX/drs/dr0xx.cpp b/test/CXX/drs/dr0xx.cpp index f8ac57f13f..70a9e49194 100644 --- a/test/CXX/drs/dr0xx.cpp +++ b/test/CXX/drs/dr0xx.cpp @@ -280,7 +280,7 @@ namespace dr27 { // dr27: yes // dr28: na -namespace dr29 { // dr29: no +namespace dr29 { // dr29: 3.4 void dr29_f0(); // expected-note {{here}} void g0() { void dr29_f0(); } extern "C++" void g0_cxx() { void dr29_f0(); } @@ -291,17 +291,14 @@ namespace dr29 { // dr29: no extern "C" void g1_c() { void dr29_f1(); } extern "C++" void g1_cxx() { void dr29_f1(); } // expected-error {{different language linkage}} - // FIXME: We should reject this. - void g2() { void dr29_f2(); } - extern "C" void dr29_f2(); + void g2() { void dr29_f2(); } // expected-note {{here}} + extern "C" void dr29_f2(); // expected-error {{different language linkage}} - // FIXME: We should reject this. - extern "C" void g3() { void dr29_f3(); } - extern "C++" void dr29_f3(); + extern "C" void g3() { void dr29_f3(); } // expected-note {{here}} + extern "C++" void dr29_f3(); // expected-error {{different language linkage}} - // FIXME: We should reject this. - extern "C++" void g4() { void dr29_f4(); } - extern "C" void dr29_f4(); + extern "C++" void g4() { void dr29_f4(); } // expected-note {{here}} + extern "C" void dr29_f4(); // expected-error {{different language linkage}} extern "C" void g5(); extern "C++" void dr29_f5(); diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp index f03f499fe1..775cf00917 100644 --- a/test/CodeGenCXX/mangle.cpp +++ b/test/CodeGenCXX/mangle.cpp @@ -9,7 +9,7 @@ struct Y { }; // CHECK: @_ZGVZN1N1gEvE1a = internal global //CHECK: @pr5966_i = external global -//CHECK: @_ZL8pr5966_i = internal global +//CHECK: @_ZL8pr5966_j = internal global // CHECK-LABEL: define zeroext i1 @_ZplRK1YRA100_P1X bool operator+(const Y&, X* (&xs)[100]) { return false; } @@ -314,10 +314,10 @@ void pr5966_foo() { pr5966_i = 0; } -static int pr5966_i; +static int pr5966_j; void pr5966_bar() { - pr5966_i = 0; + pr5966_j = 0; } namespace test0 { @@ -652,10 +652,10 @@ namespace test24 { foo(); } - static char foo() {} + static char bar() {} void test1() { - // CHECK: call signext i8 @_ZN6test24L3fooEv() - foo(); + // CHECK: call signext i8 @_ZN6test24L3barEv() + bar(); } } diff --git a/test/Index/usrs.m b/test/Index/usrs.m index dccfb75872..cc2e0fd4b4 100644 --- a/test/Index/usrs.m +++ b/test/Index/usrs.m @@ -118,7 +118,7 @@ int test_multi_declaration(void) { // CHECK: usrs.m c:objc(cs)Foo Extent=[34:1 - 45:2] // CHECK: usrs.m c:objc(cs)Foo(im)godzilla Extent=[35:1 - 39:2] // CHECK: usrs.m c:usrs.m@402objc(cs)Foo(im)godzilla@a Extent=[36:3 - 36:19] -// CHECK: usrs.m c:objc(cs)Foo(im)godzilla@z Extent=[37:3 - 37:15] +// CHECK: usrs.m c:@z Extent=[37:3 - 37:15] // CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[40:1 - 43:2] // CHECK: usrs.m c:usrs.m@470objc(cs)Foo(cm)kingkong@local_var Extent=[41:3 - 41:16] // CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[44:1 - 44:15] diff --git a/test/Sema/struct-decl.c b/test/Sema/struct-decl.c index 819e856ac8..8d3d74de76 100644 --- a/test/Sema/struct-decl.c +++ b/test/Sema/struct-decl.c @@ -57,3 +57,12 @@ const struct test2 { // expected-warning {{'const' ignored on this declaration}} inline struct test3 { // expected-error {{'inline' can only appear on functions}} int x; }; + +struct hiding_1 {}; +struct hiding_2 {}; +void test_hiding() { + struct hiding_1 *hiding_1(); + extern struct hiding_2 *hiding_2; + struct hiding_1 *p = hiding_1(); + struct hiding_2 *q = hiding_2; +} diff --git a/test/SemaCXX/blocks-1.cpp b/test/SemaCXX/blocks-1.cpp index 02e9cac62e..e11fd92cf2 100644 --- a/test/SemaCXX/blocks-1.cpp +++ b/test/SemaCXX/blocks-1.cpp @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks -std=c++11 -// expected-no-diagnostics +// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks -std=c++1y extern "C" int exit(int); @@ -57,3 +56,18 @@ namespace rdar11055105 { foo(a); }; } + +namespace LocalDecls { + void f() { + (void) ^{ + extern int a; // expected-note {{previous}} + extern int b(); // expected-note {{previous}} + }; + } + void g() { + (void) ^{ + extern float a; // expected-error {{different type}} + extern float b(); // expected-error {{cannot be overloaded}} + }; + } +} diff --git a/test/SemaCXX/cxx0x-initializer-references.cpp b/test/SemaCXX/cxx0x-initializer-references.cpp index 48236fdf76..9096c8a1c2 100644 --- a/test/SemaCXX/cxx0x-initializer-references.cpp +++ b/test/SemaCXX/cxx0x-initializer-references.cpp @@ -36,10 +36,10 @@ namespace reference { }; void call() { - void f(const int&); + one f(const int&); f({1}); - void g(int&); // expected-note {{passing argument}} + one g(int&); // expected-note {{passing argument}} g({1}); // expected-error {{cannot bind to an initializer list temporary}} int i = 0; g({i}); diff --git a/test/SemaCXX/extern-c.cpp b/test/SemaCXX/extern-c.cpp index 30b8fe69a9..2bf9535225 100644 --- a/test/SemaCXX/extern-c.cpp +++ b/test/SemaCXX/extern-c.cpp @@ -29,22 +29,42 @@ namespace test3 { } } -extern "C" { - void test4_f() { - extern int test4_b; // expected-note {{declared with C language linkage here}} +namespace N { + extern "C" { + void test4_f() { + extern int test4_b; // expected-note {{declared with C language linkage here}} + } } } static float test4_b; // expected-error {{declaration of 'test4_b' in global scope conflicts with declaration with C language linkage}} extern "C" { - void test5_f() { - extern int test5_b; // expected-note {{declared with C language linkage here}} + void test4c_f() { + extern int test4_c; // expected-note {{previous}} + } +} +static float test4_c; // expected-error {{redefinition of 'test4_c' with a different type: 'float' vs 'int'}} + +namespace N { + extern "C" { + void test5_f() { + extern int test5_b; // expected-note {{declared with C language linkage here}} + } } } extern "C" { static float test5_b; // expected-error {{declaration of 'test5_b' in global scope conflicts with declaration with C language linkage}} } +extern "C" { + void test5c_f() { + extern int test5_c; // expected-note {{previous}} + } +} +extern "C" { + static float test5_c; // expected-error {{redefinition of 'test5_c' with a different type: 'float' vs 'int'}} +} + extern "C" { void f() { extern int test6_b; diff --git a/test/SemaCXX/function-redecl.cpp b/test/SemaCXX/function-redecl.cpp index deb8e9d37f..2bc0d90cd6 100644 --- a/test/SemaCXX/function-redecl.cpp +++ b/test/SemaCXX/function-redecl.cpp @@ -4,17 +4,14 @@ int foo(int); namespace N { void f1() { void foo(int); // okay - void bar(int); + void bar(int); // expected-note 2{{previous declaration is here}} } void foo(int); // expected-note 2{{previous declaration is here}} void f2() { int foo(int); // expected-error {{functions that differ only in their return type cannot be overloaded}} - // FIXME: We should be able to diagnose the conflict between this - // declaration of 'bar' and the previous one, even though they come - // from different lexical scopes. - int bar(int); // expected-note {{previous declaration is here}} + int bar(int); // expected-error {{functions that differ only in their return type cannot be overloaded}} int baz(int); // expected-note {{previous declaration is here}} { diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp index f36300af4d..dd071258e2 100644 --- a/test/SemaCXX/warn-unreachable.cpp +++ b/test/SemaCXX/warn-unreachable.cpp @@ -62,8 +62,8 @@ void test5() { struct S { int mem; } s; - S &foor() __attribute__((noreturn)); - foor() + S &foonr() __attribute__((noreturn)); + foonr() .mem; // expected-warning {{will never be executed}} } diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html index 6ffc0e7500..d4ead30e7c 100644 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -212,7 +212,7 @@ 29 CD1 Linkage of locally declared functions - No + SVN 30