r191064 - Switch the semantic DeclContext for a block-scope declaration of a function or

Argyrios Kyrtzidis kyrtzidis at apple.com
Thu Dec 5 22:16:07 PST 2013


Hi Richard,

This commit is causing a compiler error for the attached test case, could you look into it ?

$ clang -fsyntax-only t.cpp
t.cpp:10:27: error: 'private_struct' is a private member of 'test'
  extern int array[sizeof(private_struct)];
                          ^
t.cpp:3:10: note: declared private here
  struct private_struct {
         ^
1 error generated.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: t.cpp
Type: application/octet-stream
Size: 180 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131205/62522c73/attachment.obj>
-------------- next part --------------

On Sep 19, 2013, at 6:15 PM, Richard Smith <richard-llvm at metafoo.co.uk> wrote:

> Author: rsmith
> Date: Thu Sep 19 20:15:31 2013
> New Revision: 191064
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=191064&view=rev
> Log:
> 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.
> 
> Added:
>    cfe/trunk/test/CXX/basic/basic.link/p7.cpp
> Modified:
>    cfe/trunk/include/clang/AST/Decl.h
>    cfe/trunk/include/clang/AST/DeclBase.h
>    cfe/trunk/include/clang/Sema/Lookup.h
>    cfe/trunk/include/clang/Sema/Sema.h
>    cfe/trunk/lib/Sema/SemaAccess.cpp
>    cfe/trunk/lib/Sema/SemaCodeComplete.cpp
>    cfe/trunk/lib/Sema/SemaDecl.cpp
>    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>    cfe/trunk/lib/Sema/SemaExpr.cpp
>    cfe/trunk/lib/Sema/SemaLookup.cpp
>    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
>    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
>    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
>    cfe/trunk/test/CXX/drs/dr0xx.cpp
>    cfe/trunk/test/CodeGenCXX/mangle.cpp
>    cfe/trunk/test/Index/usrs.m
>    cfe/trunk/test/Sema/struct-decl.c
>    cfe/trunk/test/SemaCXX/blocks-1.cpp
>    cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
>    cfe/trunk/test/SemaCXX/extern-c.cpp
>    cfe/trunk/test/SemaCXX/function-redecl.cpp
>    cfe/trunk/test/SemaCXX/warn-unreachable.cpp
>    cfe/trunk/www/cxx_dr_status.html
> 
> Modified: cfe/trunk/include/clang/AST/Decl.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Decl.h (original)
> +++ cfe/trunk/include/clang/AST/Decl.h Thu Sep 19 20:15:31 2013
> @@ -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<decl_type>::setPreviou
> 
>     // 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<decl_type*>(this)->IdentifierNamespace |=
> -      PrevDecl->getIdentifierNamespace() &
> +      MostRecent->getIdentifierNamespace() &
>       (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
>   } else {
>     // Make this first.
> 
> Modified: cfe/trunk/include/clang/AST/DeclBase.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/DeclBase.h (original)
> +++ cfe/trunk/include/clang/AST/DeclBase.h Thu Sep 19 20:15:31 2013
> @@ -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
> @@ -829,6 +834,32 @@ public:
>   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.
>   ///
>   /// These declarations appear in the lexical context of the friending
> @@ -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))
> 
> Modified: cfe/trunk/include/clang/Sema/Lookup.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Lookup.h?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Lookup.h (original)
> +++ cfe/trunk/include/clang/Sema/Lookup.h Thu Sep 19 20:15:31 2013
> @@ -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())
> 
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Thu Sep 19 20:15:31 2013
> @@ -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,
> 
> Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaAccess.cpp Thu Sep 19 20:15:31 2013
> @@ -1483,7 +1483,9 @@ void Sema::HandleDelayedAccessCheck(Dela
> 
>   DeclContext *DC = D->getDeclContext();
>   if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) {
> -    if (!DC->isFunctionOrMethod())
> +    if (D->getLexicalDeclContext()->isFunctionOrMethod())
> +      DC = D->getLexicalDeclContext();
> +    else
>       DC = FN;
>   } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
>     DC = cast<DeclContext>(TD->getTemplatedDecl());
> 
> Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Thu Sep 19 20:15:31 2013
> @@ -715,8 +715,8 @@ unsigned ResultBuilder::getBasePriority(
>     return CCP_Unlikely;
> 
>   // Context-based decisions.
> -  const DeclContext *DC = ND->getDeclContext()->getRedeclContext();
> -  if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) {
> +  const DeclContext *LexicalDC = ND->getLexicalDeclContext();
> +  if (LexicalDC->isFunctionOrMethod()) {
>     // _cmd is relatively rare
>     if (const ImplicitParamDecl *ImplicitParam =
>         dyn_cast<ImplicitParamDecl>(ND))
> @@ -726,6 +726,8 @@ unsigned ResultBuilder::getBasePriority(
> 
>     return CCP_LocalDeclaration;
>   }
> +
> +  const DeclContext *DC = ND->getDeclContext()->getRedeclContext();
>   if (DC->isRecord() || isa<ObjCContainerDecl>(DC))
>     return CCP_MemberDeclaration;
> 
> @@ -876,8 +878,8 @@ void ResultBuilder::MaybeAddResult(Resul
>     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<NamedDecl>(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::IsOrdinaryNonTypeNam
>   if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(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::IsIntegralConstantVa
> bool ResultBuilder::IsOrdinaryNonValueName(const NamedDecl *ND) const {
>   ND = cast<NamedDecl>(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;
> 
> 
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Sep 19 20:15:31 2013
> @@ -1020,12 +1020,12 @@ void Sema::PushOnScopeChains(NamedDecl *
>   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<VarDecl>(D) || isa<FunctionDecl>(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(FunctionDec
>       ? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
>       : 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(FunctionDec
>     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(FunctionDec
>       // 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 *Ne
>                               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
>   // 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
>   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<LinkageSpecDecl>(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,
>   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,
>   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,
>   // 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,
>       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 checkForConflictWithNonVisib
>                                                   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 *DiagnoseInvalidRedecla
>     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,
> 
>   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,
>   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,
>     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,
>   }
> 
>   // 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 ShouldWarnAboutMissingProtot
>   // Don't warn for OpenCL kernels.
>   if (FD->hasAttr<OpenCLKernelAttr>())
>     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;
> }
> 
> 
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Sep 19 20:15:31 2013
> @@ -438,9 +438,9 @@ bool Sema::MergeCXXFunctionDecl(Function
>   //   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(Function
>     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
>       // 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
> 
> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Sep 19 20:15:31 2013
> @@ -2459,7 +2459,7 @@ bool Sema::UseArgumentDependentLookup(co
>     // turn off ADL anyway).
>     if (isa<UsingShadowDecl>(D))
>       D = cast<UsingShadowDecl>(D)->getTargetDecl();
> -    else if (D->getDeclContext()->isFunctionOrMethod())
> +    else if (D->getLexicalDeclContext()->isFunctionOrMethod())
>       return false;
> 
>     // C++0x [basic.lookup.argdep]p3:
> 
> Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu Sep 19 20:15:31 2013
> @@ -223,6 +223,8 @@ static inline unsigned getIDNS(Sema::Loo
>       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<DeclContext *, bool> fi
>   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
>   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<DeclContext*>(S->getEntity());
> 
> @@ -1046,7 +1072,12 @@ bool Sema::CppLookupName(LookupResult &R
>     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, S
>         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, S
> 
>           R.resolveKind();
>         }
> +
>         return true;
>       }
>   } else {
> @@ -2858,7 +2893,11 @@ void Sema::ArgumentDependentLookup(Decla
>       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,
>       (!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) {
> 
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Sep 19 20:15:31 2013
> @@ -347,8 +347,12 @@ Decl *TemplateDeclInstantiator::VisitVar
>     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::VisitVar
>   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::VisitFun
>   }
> 
>   // 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::VisitFun
>   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::VisitFun
> 
>   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::VisitFun
>     }
>   }
> 
> +  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::VisitVar
>     return 0;
> 
>   SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs,
> -                                     StartingScope);
> +                                     Owner, StartingScope);
> 
>   return Var;
> }
> @@ -2680,7 +2695,7 @@ TemplateDeclInstantiator::InstantiateVar
>   if (VarDecl *Def = PartialSpec->getDefinition(SemaRef.getASTContext()))
>     PartialSpec = cast<VarTemplatePartialSpecializationDecl>(Def);
>   SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs,
> -                                     LateAttrs, StartingScope);
> +                                     LateAttrs, Owner, StartingScope);
>   InstPartialSpec->setInit(PartialSpec->getInit());
> 
>   return InstPartialSpec;
> @@ -3335,13 +3350,19 @@ VarTemplateSpecializationDecl *Sema::Com
> 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);
>   }
> 
> Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Thu Sep 19 20:15:31 2013
> @@ -946,7 +946,13 @@ ASTDeclReader::RedeclarableResult ASTDec
>   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(D
>   //
>   // 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);
> 
> Added: cfe/trunk/test/CXX/basic/basic.link/p7.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.link/p7.cpp?rev=191064&view=auto
> ==============================================================================
> --- cfe/trunk/test/CXX/basic/basic.link/p7.cpp (added)
> +++ cfe/trunk/test/CXX/basic/basic.link/p7.cpp Thu Sep 19 20:15:31 2013
> @@ -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<typename T>
> +  constexpr void (*f())() {
> +    void h();
> +    return &h;
> +  }
> +  static_assert(f<int>() == f<char>(), "");
> +  void h();
> +  static_assert(f<int>() == &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, "");
> +}
> 
> Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp (original)
> +++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp Thu Sep 19 20:15:31 2013
> @@ -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<typename T> 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<int>();
> -  // FIXME: Diagnose this!
> -  float n_var;
> -  template void n<double>();
> +  template void n<double>(); // expected-note {{in instantiation of}}
> +
> +  template<typename T> void o() {
> +    extern T o_var; // expected-note {{previous}}
> +    extern T o_fn(); // expected-note {{previous}}
> +  }
> +  template void o<int>();
> +  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<typename T> 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<typename T> void x() {
> +      extern T c;
> +      extern T d;
> +    }
> +    extern int d[3];
> +    template void x<int[]>();
> +  }
> +  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); }
> +  }
> }
> 
> Modified: cfe/trunk/test/CXX/drs/dr0xx.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr0xx.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/drs/dr0xx.cpp (original)
> +++ cfe/trunk/test/CXX/drs/dr0xx.cpp Thu Sep 19 20:15:31 2013
> @@ -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();
> -
> -  // FIXME: We should reject this.
> -  extern "C" void g3() { void dr29_f3(); }
> -  extern "C++" void dr29_f3();
> -
> -  // FIXME: We should reject this.
> -  extern "C++" void g4() { void dr29_f4(); }
> -  extern "C" void dr29_f4();
> +  void g2() { void dr29_f2(); } // expected-note {{here}}
> +  extern "C" void dr29_f2(); // expected-error {{different language linkage}}
> +
> +  extern "C" void g3() { void dr29_f3(); } // expected-note {{here}}
> +  extern "C++" void dr29_f3(); // expected-error {{different language linkage}}
> +
> +  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();
> 
> Modified: cfe/trunk/test/CodeGenCXX/mangle.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/mangle.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/mangle.cpp Thu Sep 19 20:15:31 2013
> @@ -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();
>   }
> }
> 
> 
> Modified: cfe/trunk/test/Index/usrs.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/usrs.m?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/test/Index/usrs.m (original)
> +++ cfe/trunk/test/Index/usrs.m Thu Sep 19 20:15:31 2013
> @@ -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 at 402objc(cs)Foo(im)godzilla at a Extent=[36:3 - 36:19]
> -// CHECK: usrs.m c:objc(cs)Foo(im)godzilla at 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 at 470objc(cs)Foo(cm)kingkong at local_var Extent=[41:3 - 41:16]
> // CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[44:1 - 44:15]
> 
> Modified: cfe/trunk/test/Sema/struct-decl.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/struct-decl.c?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/test/Sema/struct-decl.c (original)
> +++ cfe/trunk/test/Sema/struct-decl.c Thu Sep 19 20:15:31 2013
> @@ -57,3 +57,12 @@ const struct test2 { // expected-warning
> 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;
> +}
> 
> Modified: cfe/trunk/test/SemaCXX/blocks-1.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/blocks-1.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/blocks-1.cpp (original)
> +++ cfe/trunk/test/SemaCXX/blocks-1.cpp Thu Sep 19 20:15:31 2013
> @@ -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}}
> +    };
> +  }
> +}
> 
> Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp (original)
> +++ cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp Thu Sep 19 20:15:31 2013
> @@ -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});
> 
> Modified: cfe/trunk/test/SemaCXX/extern-c.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/extern-c.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/extern-c.cpp (original)
> +++ cfe/trunk/test/SemaCXX/extern-c.cpp Thu Sep 19 20:15:31 2013
> @@ -29,16 +29,27 @@ 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" {
> @@ -46,6 +57,15 @@ extern "C" {
> }
> 
> 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;
>   }
> 
> Modified: cfe/trunk/test/SemaCXX/function-redecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/function-redecl.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/function-redecl.cpp (original)
> +++ cfe/trunk/test/SemaCXX/function-redecl.cpp Thu Sep 19 20:15:31 2013
> @@ -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}}
> 
>     {
> 
> Modified: cfe/trunk/test/SemaCXX/warn-unreachable.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-unreachable.cpp?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/warn-unreachable.cpp (original)
> +++ cfe/trunk/test/SemaCXX/warn-unreachable.cpp Thu Sep 19 20:15:31 2013
> @@ -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}}
> }
> 
> 
> Modified: cfe/trunk/www/cxx_dr_status.html
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=191064&r1=191063&r2=191064&view=diff
> ==============================================================================
> --- cfe/trunk/www/cxx_dr_status.html (original)
> +++ cfe/trunk/www/cxx_dr_status.html Thu Sep 19 20:15:31 2013
> @@ -212,7 +212,7 @@
>     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#29">29</a></td>
>     <td>CD1</td>
>     <td>Linkage of locally declared functions</td>
> -    <td class="none" align="center">No</td>
> +    <td class="svn" align="center">SVN</td>
>   </tr>
>   <tr>
>     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#30">30</a></td>
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list