r289225 - Store decls in prototypes on the declarator instead of in the AST

Yung, Douglas via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 13 13:33:51 PST 2016


Hi Reid,

Following this change, we started seeing an assertion failure in one of our C tests. I have filed bug 31366 for the issue. Can you take a look?

Douglas Yung

> -----Original Message-----
> From: cfe-commits [mailto:cfe-commits-bounces at lists.llvm.org] On Behalf
> Of Reid Kleckner via cfe-commits
> Sent: Friday, December 09, 2016 9:14
> To: cfe-commits at lists.llvm.org
> Subject: r289225 - Store decls in prototypes on the declarator instead
> of in the AST
> 
> Author: rnk
> Date: Fri Dec  9 11:14:05 2016
> New Revision: 289225
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=289225&view=rev
> Log:
> Store decls in prototypes on the declarator instead of in the AST
> 
> This saves two pointers from FunctionDecl that were being used for some
> rare and questionable C-only functionality.  The DeclsInPrototypeScope
> ArrayRef was added in r151712 in order to parse this kind of C code:
> 
>     enum e {x, y};
>     int f(enum {y, x} n) {
>      return x; // should return 1, not 0
>     }
> 
> The challenge is that we parse 'int f(enum {y, x} n)' it its own
> function prototype scope that gets popped before we build the
> FunctionDecl for 'f'. The original change was doing two questionable
> things:
> 
> 1. Saving all tag decls introduced in prototype scope on a TU-global
> Sema variable. This is problematic when you have cases like this, where
> 'x' and 'y' shouldn't be visible in 'f':
>     void f(void (*fp)(enum { x, y } e)) { /* no x */ } This patch fixes
> that, so now 'f' can't see 'x', which is consistent with GCC.
> 
> 2. Storing the decls in FunctionDecl in ActOnFunctionDeclarator so that
> they could be used in ActOnStartOfFunctionDef. This is just an
> inefficient way to move information around. The AST lives forever, but
> the list of non-parameter decls in prototype scope is short lived.
> 
> Moving these things to the Declarator solves both of these issues.
> 
> Reviewers: rsmith
> 
> Subscribers: jmolloy, cfe-commits
> 
> Differential Revision: https://reviews.llvm.org/D27279
> 
> Added:
>     cfe/trunk/test/PCH/decl-in-prototype.c
> Modified:
>     cfe/trunk/include/clang/AST/Decl.h
>     cfe/trunk/include/clang/Sema/DeclSpec.h
>     cfe/trunk/include/clang/Sema/Sema.h
>     cfe/trunk/lib/AST/ASTDumper.cpp
>     cfe/trunk/lib/AST/Decl.cpp
>     cfe/trunk/lib/Parse/ParseDecl.cpp
>     cfe/trunk/lib/Parse/ParseExpr.cpp
>     cfe/trunk/lib/Parse/ParseExprCXX.cpp
>     cfe/trunk/lib/Sema/DeclSpec.cpp
>     cfe/trunk/lib/Sema/SemaDecl.cpp
>     cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
>     cfe/trunk/lib/Sema/SemaType.cpp
>     cfe/trunk/test/Misc/ast-dump-decl.c
>     cfe/trunk/test/Sema/decl-in-prototype.c
>     cfe/trunk/test/SemaCXX/type-definition-in-specifier.cpp
> 
> Modified: cfe/trunk/include/clang/AST/Decl.h
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/include/clang/AST/Decl.h?rev=289225&r1=289224&r2=2892
> 25&view=diff
> =======================================================================
> =======
> --- cfe/trunk/include/clang/AST/Decl.h (original)
> +++ cfe/trunk/include/clang/AST/Decl.h Fri Dec  9 11:14:05 2016
> @@ -1601,11 +1601,6 @@ private:
>    /// no formals.
>    ParmVarDecl **ParamInfo;
> 
> -  /// DeclsInPrototypeScope - Array of pointers to NamedDecls for
> -  /// decls defined in the function prototype that are not parameters.
> E.g.
> -  /// 'enum Y' in 'void f(enum Y {AA} x) {}'.
> -  ArrayRef<NamedDecl *> DeclsInPrototypeScope;
> -
>    LazyDeclStmtPtr Body;
> 
>    // FIXME: This can be packed into the bitfields in DeclContext.
> @@ -2050,11 +2045,6 @@ public:
>      setParams(getASTContext(), NewParamInfo);
>    }
> 
> -  ArrayRef<NamedDecl *> getDeclsInPrototypeScope() const {
> -    return DeclsInPrototypeScope;
> -  }
> -  void setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls);
> -
>    /// getMinRequiredArguments - Returns the minimum number of
> arguments
>    /// needed to call this function. This may be fewer than the number
> of
>    /// function parameters, if some of the parameters have default
> 
> Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=289225&r1=289224&r2
> =289225&view=diff
> =======================================================================
> =======
> --- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
> +++ cfe/trunk/include/clang/Sema/DeclSpec.h Fri Dec  9 11:14:05 2016
> @@ -1248,9 +1248,10 @@ struct DeclaratorChunk {
>      /// declarator.
>      unsigned NumParams;
> 
> -    /// NumExceptions - This is the number of types in the dynamic-
> exception-
> -    /// decl, if the function has one.
> -    unsigned NumExceptions;
> +    /// NumExceptionsOrDecls - This is the number of types in the
> +    /// dynamic-exception-decl, if the function has one. In C, this is
> the
> +    /// number of declarations in the function prototype.
> +    unsigned NumExceptionsOrDecls;
> 
>      /// \brief The location of the ref-qualifier, if any.
>      ///
> @@ -1300,6 +1301,11 @@ struct DeclaratorChunk {
>        /// \brief Pointer to the cached tokens for an exception-
> specification
>        /// that has not yet been parsed.
>        CachedTokens *ExceptionSpecTokens;
> +
> +      /// Pointer to a new[]'d array of declarations that need to be
> available
> +      /// for lookup inside the function body, if one exists. Does not
> exist in
> +      /// C++.
> +      NamedDecl **DeclsInPrototype;
>      };
> 
>      /// \brief If HasTrailingReturnType is true, this is the trailing
> return @@ -1322,10 +1328,20 @@ struct DeclaratorChunk {
>      void destroy() {
>        if (DeleteParams)
>          delete[] Params;
> -      if (getExceptionSpecType() == EST_Dynamic)
> +      switch (getExceptionSpecType()) {
> +      default:
> +        break;
> +      case EST_Dynamic:
>          delete[] Exceptions;
> -      else if (getExceptionSpecType() == EST_Unparsed)
> +        break;
> +      case EST_Unparsed:
>          delete ExceptionSpecTokens;
> +        break;
> +      case EST_None:
> +        if (NumExceptionsOrDecls != 0)
> +          delete[] DeclsInPrototype;
> +        break;
> +      }
>      }
> 
>      /// isKNRPrototype - Return true if this is a K&R style identifier
> list, @@ -1395,6 +1411,19 @@ struct DeclaratorChunk {
>        return
> static_cast<ExceptionSpecificationType>(ExceptionSpecType);
>      }
> 
> +    /// \brief Get the number of dynamic exception specifications.
> +    unsigned getNumExceptions() const {
> +      assert(ExceptionSpecType != EST_None);
> +      return NumExceptionsOrDecls;
> +    }
> +
> +    /// \brief Get the non-parameter decls defined within this
> function
> +    /// prototype. Typically these are tag declarations.
> +    ArrayRef<NamedDecl *> getDeclsInPrototype() const {
> +      assert(ExceptionSpecType == EST_None);
> +      return llvm::makeArrayRef(DeclsInPrototype,
> NumExceptionsOrDecls);
> +    }
> +
>      /// \brief Determine whether this function declarator had a
>      /// trailing-return-type.
>      bool hasTrailingReturnType() const { return HasTrailingReturnType;
> } @@ -1540,6 +1569,7 @@ struct DeclaratorChunk {
>                                       unsigned NumExceptions,
>                                       Expr *NoexceptExpr,
>                                       CachedTokens
> *ExceptionSpecTokens,
> +                                     ArrayRef<NamedDecl *>
> + DeclsInPrototype,
>                                       SourceLocation LocalRangeBegin,
>                                       SourceLocation LocalRangeEnd,
>                                       Declarator &TheDeclarator,
> 
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/include/clang/Sema/Sema.h?rev=289225&r1=289224&r2=289
> 225&view=diff
> =======================================================================
> =======
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Fri Dec  9 11:14:05 2016
> @@ -1527,12 +1527,6 @@ public:
>      NamedDecl *Previous;
>    };
> 
> -  /// List of decls defined in a function prototype. This contains
> EnumConstants
> -  /// that incorrectly end up in translation unit scope because there
> is no
> -  /// function to pin them on. ActOnFunctionDeclarator reads this list
> and patches
> -  /// them into the FunctionDecl.
> -  std::vector<NamedDecl*> DeclsInPrototypeScope;
> -
>    DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType =
> nullptr);
> 
>    void DiagnoseUseOfUnimplementedSelectors();
> 
> Modified: cfe/trunk/lib/AST/ASTDumper.cpp
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=289225&r1=289224&r2=289225&
> view=diff
> =======================================================================
> =======
> --- cfe/trunk/lib/AST/ASTDumper.cpp (original)
> +++ cfe/trunk/lib/AST/ASTDumper.cpp Fri Dec  9 11:14:05 2016
> @@ -1164,11 +1164,6 @@ void ASTDumper::VisitFunctionDecl(const
>            D->getTemplateSpecializationInfo())
>      dumpTemplateArgumentList(*FTSI->TemplateArguments);
> 
> -  for (ArrayRef<NamedDecl *>::iterator
> -       I = D->getDeclsInPrototypeScope().begin(),
> -       E = D->getDeclsInPrototypeScope().end(); I != E; ++I)
> -    dumpDecl(*I);
> -
>    if (!D->param_begin() && D->getNumParams())
>      dumpChild([=] { OS << "<<NULL params x " << D->getNumParams() <<
> ">>"; });
>    else
> 
> Modified: cfe/trunk/lib/AST/Decl.cpp
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/lib/AST/Decl.cpp?rev=289225&r1=289224&r2=289225&view=
> diff
> =======================================================================
> =======
> --- cfe/trunk/lib/AST/Decl.cpp (original)
> +++ cfe/trunk/lib/AST/Decl.cpp Fri Dec  9 11:14:05 2016
> @@ -2840,28 +2840,6 @@ void FunctionDecl::setParams(ASTContext
>    }
>  }
> 
> -void FunctionDecl::setDeclsInPrototypeScope(ArrayRef<NamedDecl *>
> NewDecls) {
> -  assert(DeclsInPrototypeScope.empty() && "Already has prototype
> decls!");
> -
> -  if (!NewDecls.empty()) {
> -    NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()];
> -    std::copy(NewDecls.begin(), NewDecls.end(), A);
> -    DeclsInPrototypeScope = llvm::makeArrayRef(A, NewDecls.size());
> -    // Move declarations introduced in prototype to the function
> context.
> -    for (auto I : NewDecls) {
> -      DeclContext *DC = I->getDeclContext();
> -      // Forward-declared reference to an enumeration is not added to
> -      // declaration scope, so skip declaration that is absent from
> its
> -      // declaration contexts.
> -      if (DC->containsDecl(I)) {
> -          DC->removeDecl(I);
> -          I->setDeclContext(this);
> -          addDecl(I);
> -      }
> -    }
> -  }
> -}
> -
>  /// getMinRequiredArguments - Returns the minimum number of arguments
> /// needed to call this function. This may be fewer than the number of
> /// function parameters, if some of the parameters have default
> 
> Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=289225&r1=289224&r2=28922
> 5&view=diff
> =======================================================================
> =======
> --- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Dec  9 11:14:05 2016
> @@ -5827,6 +5827,21 @@ void Parser::ParseFunctionDeclarator(Dec
>      }
>    }
> 
> +  // Collect non-parameter declarations from the prototype if this is
> a
> + function  // declaration. They will be moved into the scope of the
> + function. Only do  // this in C and not C++, where the decls will
> + continue to live in the  // surrounding context.
> +  SmallVector<NamedDecl *, 0> DeclsInPrototype;  if
> + (getCurScope()->getFlags() & Scope::FunctionDeclarationScope &&
> +      !getLangOpts().CPlusPlus) {
> +    for (Decl *D : getCurScope()->decls()) {
> +      NamedDecl *ND = dyn_cast<NamedDecl>(D);
> +      if (!ND || isa<ParmVarDecl>(ND))
> +        continue;
> +      DeclsInPrototype.push_back(ND);
> +    }
> +  }
> +
>    // Remember that we parsed a function type, and remember the
> attributes.
>    D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto,
>                                               IsAmbiguous, @@ -5846,6
> +5861,7 @@ void Parser::ParseFunctionDeclarator(Dec
>                                               NoexceptExpr.isUsable() ?
>                                                 NoexceptExpr.get() :
> nullptr,
>                                               ExceptionSpecTokens,
> +                                             DeclsInPrototype,
>                                               StartLoc, LocalEndLoc, D,
>                                               TrailingReturnType),
>                  FnAttrs, EndLoc);
> 
> Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=289225&r1=289224&r2=28922
> 5&view=diff
> =======================================================================
> =======
> --- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseExpr.cpp Fri Dec  9 11:14:05 2016
> @@ -2842,6 +2842,7 @@ ExprResult Parser::ParseBlockLiteralExpr
>                                               /*NumExceptions=*/0,
>                                               /*NoexceptExpr=*/nullptr,
> 
> /*ExceptionSpecTokens=*/nullptr,
> +
> /*DeclsInPrototype=*/None,
>                                               CaretLoc, CaretLoc,
>                                               ParamInfo),
>                            attrs, CaretLoc);
> 
> Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=289225&r1=289224&r2=28
> 9225&view=diff
> =======================================================================
> =======
> --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Fri Dec  9 11:14:05 2016
> @@ -1244,6 +1244,7 @@ ExprResult Parser::ParseLambdaExpression
>                                             NoexceptExpr.isUsable() ?
>                                               NoexceptExpr.get() :
> nullptr,
> 
> /*ExceptionSpecTokens*/nullptr,
> +                                           /*DeclsInPrototype=*/None,
>                                             LParenLoc,
> FunLocalRangeEnd, D,
>                                             TrailingReturnType),
>                    Attr, DeclEndLoc);
> @@ -1313,6 +1314,7 @@ ExprResult Parser::ParseLambdaExpression
>                                                 /*NumExceptions=*/0,
> 
> /*NoexceptExpr=*/nullptr,
> 
> /*ExceptionSpecTokens=*/nullptr,
> +
> + /*DeclsInPrototype=*/None,
>                                                 DeclLoc, DeclEndLoc, D,
>                                                 TrailingReturnType),
>                    Attr, DeclEndLoc);
> 
> Modified: cfe/trunk/lib/Sema/DeclSpec.cpp
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=289225&r1=289224&r2=289225&
> view=diff
> =======================================================================
> =======
> --- cfe/trunk/lib/Sema/DeclSpec.cpp (original)
> +++ cfe/trunk/lib/Sema/DeclSpec.cpp Fri Dec  9 11:14:05 2016
> @@ -173,6 +173,8 @@ DeclaratorChunk DeclaratorChunk::getFunc
>                                               unsigned NumExceptions,
>                                               Expr *NoexceptExpr,
>                                               CachedTokens
> *ExceptionSpecTokens,
> +                                             ArrayRef<NamedDecl*>
> +                                                 DeclsInPrototype,
>                                               SourceLocation
> LocalRangeBegin,
>                                               SourceLocation
> LocalRangeEnd,
>                                               Declarator
> &TheDeclarator, @@ -204,7 +206,7 @@ DeclaratorChunk
> DeclaratorChunk::getFunc
>    I.Fun.ExceptionSpecType       = ESpecType;
>    I.Fun.ExceptionSpecLocBeg     =
> ESpecRange.getBegin().getRawEncoding();
>    I.Fun.ExceptionSpecLocEnd     =
> ESpecRange.getEnd().getRawEncoding();
> -  I.Fun.NumExceptions           = 0;
> +  I.Fun.NumExceptionsOrDecls    = 0;
>    I.Fun.Exceptions              = nullptr;
>    I.Fun.NoexceptExpr            = nullptr;
>    I.Fun.HasTrailingReturnType   = TrailingReturnType.isUsable() ||
> @@ -240,7 +242,7 @@ DeclaratorChunk DeclaratorChunk::getFunc
>    case EST_Dynamic:
>      // new[] an exception array if needed
>      if (NumExceptions) {
> -      I.Fun.NumExceptions = NumExceptions;
> +      I.Fun.NumExceptionsOrDecls = NumExceptions;
>        I.Fun.Exceptions = new
> DeclaratorChunk::TypeAndRange[NumExceptions];
>        for (unsigned i = 0; i != NumExceptions; ++i) {
>          I.Fun.Exceptions[i].Ty = Exceptions[i]; @@ -257,6 +259,17 @@
> DeclaratorChunk DeclaratorChunk::getFunc
>      I.Fun.ExceptionSpecTokens = ExceptionSpecTokens;
>      break;
>    }
> +
> +  if (!DeclsInPrototype.empty()) {
> +    assert(ESpecType == EST_None && NumExceptions == 0 &&
> +           "cannot have exception specifiers and decls in prototype");
> +    I.Fun.NumExceptionsOrDecls = DeclsInPrototype.size();
> +    // Copy the array of decls into stable heap storage.
> +    I.Fun.DeclsInPrototype = new NamedDecl *[DeclsInPrototype.size()];
> +    for (size_t J = 0; J < DeclsInPrototype.size(); ++J)
> +      I.Fun.DeclsInPrototype[J] = DeclsInPrototype[J];  }
> +
>    return I;
>  }
> 
> 
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=289225&r1=289224&r2=289225&
> view=diff
> =======================================================================
> =======
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Dec  9 11:14:05 2016
> @@ -8222,8 +8222,9 @@ Sema::ActOnFunctionDeclarator(Scope *S,
>    // Copy the parameter declarations from the declarator D to the
> function
>    // declaration NewFD, if they are available.  First scavenge them
> into Params.
>    SmallVector<ParmVarDecl*, 16> Params;
> -  if (D.isFunctionDeclarator()) {
> -    DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
> +  unsigned FTIIdx;
> +  if (D.isFunctionDeclarator(FTIIdx)) {
> +    DeclaratorChunk::FunctionTypeInfo &FTI =
> + D.getTypeObject(FTIIdx).Fun;
> 
>      // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs
>      // function that takes no arguments, not a function that takes a
> @@ -8241,6 +8242,19 @@ Sema::ActOnFunctionDeclarator(Scope *S,
>            NewFD->setInvalidDecl();
>        }
>      }
> +
> +    if (!getLangOpts().CPlusPlus) {
> +      // In C, find all the non-parameter declarations from the
> prototype and
> +      // move them into the new function decl context as well.
> Typically they
> +      // will have been added to the surrounding context of the
> prototype.
> +      for (NamedDecl *NonParmDecl : FTI.getDeclsInPrototype()) {
> +        DeclContext *OldDC = NonParmDecl->getDeclContext();
> +        if (OldDC->containsDecl(NonParmDecl))
> +          OldDC->removeDecl(NonParmDecl);
> +        NonParmDecl->setDeclContext(NewFD);
> +        NewFD->addDecl(NonParmDecl);
> +      }
> +    }
>    } else if (const FunctionProtoType *FT = R-
> >getAs<FunctionProtoType>()) {
>      // When we're declaring a function with a typedef, typeof, etc as
> in the
>      // following example, we'll need to synthesize (unnamed) @@ -
> 8266,15 +8280,6 @@ Sema::ActOnFunctionDeclarator(Scope *S,
>    // Finally, we know we have the right number of parameters, install
> them.
>    NewFD->setParams(Params);
> 
> -  // Find all anonymous symbols defined during the declaration of this
> function
> -  // and add to NewFD. This lets us track decls such 'enum Y' in:
> -  //
> -  //   void f(enum Y {AA} x) {}
> -  //
> -  // which would otherwise incorrectly end up in the translation unit
> scope.
> -  NewFD->setDeclsInPrototypeScope(DeclsInPrototypeScope);
> -  DeclsInPrototypeScope.clear();
> -
>    if (D.getDeclSpec().isNoreturnSpecified())
>      NewFD->addAttr(
>          ::new(Context)
> C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(),
> @@ -11632,6 +11637,29 @@ Decl *Sema::ActOnStartOfFunctionDef(Scop
>    CheckParmsForFunctionDef(FD->parameters(),
>                             /*CheckParameterNames=*/true);
> 
> +  // Add non-parameter declarations already in the function to the
> + current  // scope.
> +  if (FnBodyScope) {
> +    for (Decl *NPD : FD->decls()) {
> +      auto *NonParmDecl = dyn_cast<NamedDecl>(NPD);
> +      if (!NonParmDecl)
> +        continue;
> +      assert(!isa<ParmVarDecl>(NonParmDecl) &&
> +             "parameters should not be in newly created FD yet");
> +
> +      // If the decl has a name, make it accessible in the current
> scope.
> +      if (NonParmDecl->getDeclName())
> +        PushOnScopeChains(NonParmDecl, FnBodyScope,
> + /*AddToContext=*/false);
> +
> +      // Similarly, dive into enums and fish their constants out,
> making them
> +      // accessible in this scope.
> +      if (auto *ED = dyn_cast<EnumDecl>(NonParmDecl)) {
> +        for (auto *EI : ED->enumerators())
> +          PushOnScopeChains(EI, FnBodyScope, /*AddToContext=*/false);
> +      }
> +    }
> +  }
> +
>    // Introduce our parameters into the function scope
>    for (auto Param : FD->parameters()) {
>      Param->setOwningFunction(FD);
> @@ -11644,39 +11672,6 @@ Decl *Sema::ActOnStartOfFunctionDef(Scop
>      }
>    }
> 
> -  // If we had any tags defined in the function prototype,
> -  // introduce them into the function scope.
> -  if (FnBodyScope) {
> -    for (ArrayRef<NamedDecl *>::iterator
> -             I = FD->getDeclsInPrototypeScope().begin(),
> -             E = FD->getDeclsInPrototypeScope().end();
> -         I != E; ++I) {
> -      NamedDecl *D = *I;
> -
> -      // Some of these decls (like enums) may have been pinned to the
> -      // translation unit for lack of a real context earlier. If so,
> remove
> -      // from the translation unit and reattach to the current
> context.
> -      if (D->getLexicalDeclContext() ==
> Context.getTranslationUnitDecl()) {
> -        // Is the decl actually in the context?
> -        if (Context.getTranslationUnitDecl()->containsDecl(D))
> -          Context.getTranslationUnitDecl()->removeDecl(D);
> -        // Either way, reassign the lexical decl context to our
> FunctionDecl.
> -        D->setLexicalDeclContext(CurContext);
> -      }
> -
> -      // If the decl has a non-null name, make accessible in the
> current scope.
> -      if (!D->getName().empty())
> -        PushOnScopeChains(D, FnBodyScope, /*AddToContext=*/false);
> -
> -      // Similarly, dive into enums and fish their constants out,
> making them
> -      // accessible in this scope.
> -      if (auto *ED = dyn_cast<EnumDecl>(D)) {
> -        for (auto *EI : ED->enumerators())
> -          PushOnScopeChains(EI, FnBodyScope, /*AddToContext=*/false);
> -      }
> -    }
> -  }
> -
>    // Ensure that the function's exception specification is
> instantiated.
>    if (const FunctionProtoType *FPT = FD->getType()-
> >getAs<FunctionProtoType>())
>      ResolveExceptionSpec(D->getLocation(), FPT); @@ -12161,6 +12156,7
> @@ NamedDecl *Sema::ImplicitlyDefineFunctio
>                                               /*NumExceptions=*/0,
>                                               /*NoexceptExpr=*/nullptr,
> 
> /*ExceptionSpecTokens=*/nullptr,
> +
> /*DeclsInPrototype=*/None,
>                                               Loc, Loc, D),
>                  DS.getAttributes(),
>                  SourceLocation());
> @@ -13430,7 +13426,6 @@ CreateNewDecl:
>      } else if (!PrevDecl) {
>        Diag(Loc, diag::warn_decl_in_param_list) <<
> Context.getTagDeclType(New);
>      }
> -    DeclsInPrototypeScope.push_back(New);
>    }
> 
>    if (Invalid)
> 
> Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=289225&r1=28922
> 4&r2=289225&view=diff
> =======================================================================
> =======
> --- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Fri Dec  9 11:14:05
> 2016
> @@ -772,7 +772,7 @@ bool Sema::containsUnexpandedParameterPa
>        }
> 
>        if (Chunk.Fun.getExceptionSpecType() == EST_Dynamic) {
> -        for (unsigned i = 0; i != Chunk.Fun.NumExceptions; ++i) {
> +        for (unsigned i = 0; i != Chunk.Fun.getNumExceptions(); ++i) {
>            if (Chunk.Fun.Exceptions[i]
>                    .Ty.get()
>                    ->containsUnexpandedParameterPack())
> 
> Modified: cfe/trunk/lib/Sema/SemaType.cpp
> URL: http://llvm.org/viewvc/llvm-
> project/cfe/trunk/lib/Sema/SemaType.cpp?rev=289225&r1=289224&r2=289225&
> view=diff
> =======================================================================
> =======
> --- cfe/trunk/lib/Sema/SemaType.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaType.cpp Fri Dec  9 11:14:05 2016
> @@ -718,6 +718,7 @@ static void maybeSynthesizeBlockSignatur
>        /*NumExceptions=*/0,
>        /*NoexceptExpr=*/nullptr,
>        /*ExceptionSpecTokens=*/nullptr,
> +      /*DeclsInPrototype=*/None,
>        loc, loc, declarator));
> 
>    // For consistency, make sure the state still has us as processing
> @@ -4469,7 +4470,7 @@ static TypeSourceInfo *GetFullTypeForDec
>          if (FTI.getExceptionSpecType() == EST_Dynamic) {
>            // FIXME: It's rather inefficient to have to split into two
> vectors
>            // here.
> -          unsigned N = FTI.NumExceptions;
> +          unsigned N = FTI.getNumExceptions();
>            DynamicExceptions.reserve(N);
>            DynamicExceptionRanges.reserve(N);
>            for (unsigned I = 0; I != N; ++I) {
> 
> Modified: cfe/trunk/test/Misc/ast-dump-decl.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/ast-dump-
> decl.c?rev=289225&r1=289224&r2=289225&view=diff
> =======================================================================
> =======
> --- cfe/trunk/test/Misc/ast-dump-decl.c (original)
> +++ cfe/trunk/test/Misc/ast-dump-decl.c Fri Dec  9 11:14:05 2016
> @@ -102,16 +102,22 @@ struct testIndirectFieldDecl {
>  // CHECK-NEXT:   Field{{.*}} ''
>  // CHECK-NEXT:   Field{{.*}} 'TestIndirectFieldDecl'
> 
> +// FIXME: It would be nice to dump the enum and its enumerators.
>  int TestFunctionDecl(int x, enum { e } y) {
>    return x;
>  }
>  // CHECK:      FunctionDecl{{.*}} TestFunctionDecl 'int (int, enum
> {{.*}})'
> -// CHECK-NEXT:   EnumDecl
> -// CHECK-NEXT:     EnumConstantDecl{{.*}} e
>  // CHECK-NEXT:   ParmVarDecl{{.*}} x
>  // CHECK-NEXT:   ParmVarDecl{{.*}} y
>  // CHECK-NEXT:   CompoundStmt
> 
> +// FIXME: It would be nice to 'Enum' and 'e'.
> +int TestFunctionDecl2(enum Enum { e } x) { return x; }
> +// CHECK:      FunctionDecl{{.*}} TestFunctionDecl2 'int (enum
> {{.*}})'
> +// CHECK-NEXT:   ParmVarDecl{{.*}} x
> +// CHECK-NEXT:   CompoundStmt
> +
> +
>  int TestFunctionDeclProto(int x);
>  // CHECK:      FunctionDecl{{.*}} TestFunctionDeclProto 'int (int)'
>  // CHECK-NEXT:   ParmVarDecl{{.*}} x
> 
> Added: cfe/trunk/test/PCH/decl-in-prototype.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/decl-in-
> prototype.c?rev=289225&view=auto
> =======================================================================
> =======
> --- cfe/trunk/test/PCH/decl-in-prototype.c (added)
> +++ cfe/trunk/test/PCH/decl-in-prototype.c Fri Dec  9 11:14:05 2016
> @@ -0,0 +1,27 @@
> +// Test that we serialize the enum decl in the function prototype
> somehow.
> +// These decls aren't serialized quite the same way as parameters.
> +
> +// Test this without pch.
> +// RUN: %clang_cc1 -include %s -emit-llvm -o - %s | FileCheck %s
> +
> +// Test with pch.
> +// RUN: %clang_cc1 -emit-pch -o %t %s
> +// RUN: %clang_cc1 -include-pch %t -emit-llvm -o - %s | FileCheck %s
> +
> +// CHECK-LABEL: define i32 @main()
> +// CHECK:   ret i32 1
> +
> +#ifndef HEADER
> +#define HEADER
> +
> +static inline __attribute__((always_inline)) f(enum { x, y } p) {
> +  return y;
> +}
> +
> +#else
> +
> +int main() {
> +  return f(0);
> +}
> +
> +#endif
> 
> Modified: cfe/trunk/test/Sema/decl-in-prototype.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/decl-in-
> prototype.c?rev=289225&r1=289224&r2=289225&view=diff
> =======================================================================
> =======
> --- cfe/trunk/test/Sema/decl-in-prototype.c (original)
> +++ cfe/trunk/test/Sema/decl-in-prototype.c Fri Dec  9 11:14:05 2016
> @@ -1,13 +1,19 @@
>  // RUN: %clang_cc1 -fsyntax-only -verify %s
> 
> +#define SA(n, c) int arr##n[(c) ? 1 : -1] = {}
> +
>  const int AA = 5;
> 
>  int f1(enum {AA,BB} E) { // expected-warning {{will not be visible
> outside of this function}}
> -    return BB;
> +  SA(1, AA == 0);
> +  SA(2, BB == 1);
> +  return BB;
>  }
> 
>  int f2(enum {AA=7,BB} E) { // expected-warning {{will not be visible
> outside of this function}}
> -    return AA;
> +  SA(1, AA == 7);
> +  SA(2, BB == 8);
> +  return AA;
>  }
> 
>  struct a {
> @@ -38,3 +44,11 @@ enum e19018 qq; //expected-error{{tentat
> 
>  // Only warn once, even if we create two declarations.
>  void f(struct q *, struct __attribute__((aligned(4))) q *); //
> expected-warning {{will not be visible outside}}
> +
> +// This enum inside the function pointer parameter shouldn't leak into
> +the // function.
> +enum { BB = 0 };
> +void enum_in_fun_in_fun(void (*fp)(enum { AA, BB } e)) { //
> +expected-warning {{will not be visible}}
> +  SA(1, AA == 5);
> +  SA(2, BB == 0);
> +}
> 
> Modified: cfe/trunk/test/SemaCXX/type-definition-in-specifier.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-
> definition-in-specifier.cpp?rev=289225&r1=289224&r2=289225&view=diff
> =======================================================================
> =======
> --- cfe/trunk/test/SemaCXX/type-definition-in-specifier.cpp (original)
> +++ cfe/trunk/test/SemaCXX/type-definition-in-specifier.cpp Fri Dec  9
> +++ 11:14:05 2016
> @@ -1,4 +1,4 @@
> -// RUN: %clang_cc1 -fsyntax-only -verify %s
> +// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -verify %s
> 
>  struct S0;
>  struct S1;
> @@ -30,7 +30,7 @@ struct pr19018 {
> 
>  void pr19018_1 (enum e19018_1 {qq} x); // expected-error{{cannot be
> defined in a parameter type}}  void pr19018_1a (enum e19018_1 {qq} x);
> // expected-error{{cannot be defined in a parameter type}}
> -e19018_1 x2;  // expected-error{{unknown type name 'e19018_1'}}
> +e19018_1 x2;
> 
>  void pr19018_2 (enum {qq} x); // expected-error{{cannot be defined in
> a parameter type}}  void pr19018_3 (struct s19018_2 {int qq;} x); //
> expected-error{{cannot be defined in a parameter type}} @@ -53,14
> +53,19 @@ struct pr19018a {
> 
>  struct s19018b {
>    void func1 (enum en_2 {qq} x); // expected-error{{cannot be defined
> in a parameter type}}
> -  en_2 x1;  // expected-error{{unknown type name 'en_2'}}
> +  en_2 x1;
>    void func2 (enum en_3 {qq} x); // expected-error{{cannot be defined
> in a parameter type}}
> -  enum en_3 x2; // expected-error{{ISO C++ forbids forward references
> to 'enum' types}} \
> -                // expected-error{{field has incomplete type 'enum
> en_3'}} \
> -                // expected-note{{forward declaration of 'en_3'}}
> +  enum en_3 x2;
>  };
> 
>  struct pr18963 {
> -  short bar5 (struct foo4 {} bar2); // expected-error{{'foo4' cannot
> be defined in a parameter type}}
> -  long foo5 (float foo6 = foo4);  // expected-error{{use of undeclared
> identifier 'foo4'}}
> +  short bar5 (struct foo4 {} bar2); // expected-error{{'foo4' cannot
> be defined in a parameter type}} \
> +                                    // expected-note{{declared here}}
> +
> +  long foo5 (float foo6 = foo4);  // expected-error{{'foo4' does not
> + refer to a value}}
>  };
> +
> +// expected-error at +2 {{cannot be defined in a parameter type}} //
> +expected-note at +1 {{previous definition is here}} void
> +func_with_eh_and_type(struct type_in_eh {} o) throw(int) {} struct
> +type_in_eh {}; // expected-error {{redefinition of 'type_in_eh'}}
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


More information about the cfe-commits mailing list