Index: cfe/trunk/include/clang/AST/Decl.h =================================================================== --- cfe/trunk/include/clang/AST/Decl.h +++ cfe/trunk/include/clang/AST/Decl.h @@ -1632,6 +1632,11 @@ /// skipped. unsigned HasSkippedBody : 1; + /// Indicates if the function declaration will have a body, once we're done + /// parsing it. (We don't set it to false when we're done parsing, in the + /// hopes this is simpler.) + unsigned WillHaveBody : 1; + /// \brief End part of this FunctionDecl's source range. /// /// We could compute the full range in getSourceRange(). However, when we're @@ -1701,25 +1706,21 @@ protected: FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - StorageClass S, bool isInlineSpecified, + const DeclarationNameInfo &NameInfo, QualType T, + TypeSourceInfo *TInfo, StorageClass S, bool isInlineSpecified, bool isConstexprSpecified) - : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, - StartLoc), - DeclContext(DK), - redeclarable_base(C), - ParamInfo(nullptr), Body(), - SClass(S), - IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified), - IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), - HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), - IsDefaulted(false), IsExplicitlyDefaulted(false), - HasImplicitReturnZero(false), IsLateTemplateParsed(false), - IsConstexpr(isConstexprSpecified), UsesSEHTry(false), - HasSkippedBody(false), EndRangeLoc(NameInfo.getEndLoc()), - TemplateOrSpecialization(), - DNLoc(NameInfo.getInfo()) {} + : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, + StartLoc), + DeclContext(DK), redeclarable_base(C), ParamInfo(nullptr), Body(), + SClass(S), IsInline(isInlineSpecified), + IsInlineSpecified(isInlineSpecified), IsVirtualAsWritten(false), + IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true), + IsDeleted(false), IsTrivial(false), IsDefaulted(false), + IsExplicitlyDefaulted(false), HasImplicitReturnZero(false), + IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified), + UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false), + EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(), + DNLoc(NameInfo.getInfo()) {} typedef Redeclarable redeclarable_base; FunctionDecl *getNextRedeclarationImpl() override { @@ -2001,6 +2002,10 @@ bool hasSkippedBody() const { return HasSkippedBody; } void setHasSkippedBody(bool Skipped = true) { HasSkippedBody = Skipped; } + /// True if this function will eventually have a body, once it's fully parsed. + bool willHaveBody() const { return WillHaveBody; } + void setWillHaveBody(bool V = true) { WillHaveBody = V; } + void setPreviousDeclaration(FunctionDecl * PrevDecl); FunctionDecl *getCanonicalDecl() override; Index: cfe/trunk/lib/AST/Decl.cpp =================================================================== --- cfe/trunk/lib/AST/Decl.cpp +++ cfe/trunk/lib/AST/Decl.cpp @@ -2933,7 +2933,7 @@ /// of redeclarations of the given functions causes /// isInlineDefinitionExternallyVisible to change from false to true. bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { - assert(!doesThisDeclarationHaveABody() && + assert(!doesThisDeclarationHaveABody() && !willHaveBody() && "Must have a declaration without a body."); ASTContext &Context = getASTContext(); @@ -3048,7 +3048,8 @@ /// an externally visible symbol, but "extern inline" will not create an /// externally visible symbol. bool FunctionDecl::isInlineDefinitionExternallyVisible() const { - assert(doesThisDeclarationHaveABody() && "Must have the function definition"); + assert(doesThisDeclarationHaveABody() || + willHaveBody() && "Must be a function definition"); assert(isInlined() && "Function must be inline"); ASTContext &Context = getASTContext(); Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -5762,23 +5762,7 @@ return false; // Okay, go ahead and call the relatively-more-expensive function. - -#ifndef NDEBUG - // AST quite reasonably asserts that it's working on a function - // definition. We don't really have a way to tell it that we're - // currently defining the function, so just lie to it in +Asserts - // builds. This is an awful hack. - FD->setLazyBody(1); -#endif - - bool isC99Inline = - S.Context.GetGVALinkageForFunction(FD) == GVA_AvailableExternally; - -#ifndef NDEBUG - FD->setLazyBody(0); -#endif - - return isC99Inline; + return S.Context.GetGVALinkageForFunction(FD) == GVA_AvailableExternally; } /// Determine whether a variable is extern "C" prior to attaching @@ -11487,6 +11471,11 @@ return D; } + // Mark this function as "will have a body eventually". This lets users to + // call e.g. isInlineDefinitionExternallyVisible while we're still parsing + // this function. + FD->setWillHaveBody(); + // If we are instantiating a generic lambda call operator, push // a LambdaScopeInfo onto the function stack. But use the information // that's already been calculated (ActOnLambdaExpr) to prime the current Index: cfe/trunk/test/SemaCUDA/gnu-inline.cu =================================================================== --- cfe/trunk/test/SemaCUDA/gnu-inline.cu +++ cfe/trunk/test/SemaCUDA/gnu-inline.cu @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +#include "Inputs/cuda.h" + +// expected-no-diagnostics + +// Check that we can handle gnu_inline functions when compiling in CUDA mode. + +void foo(); +inline __attribute__((gnu_inline)) void bar() { foo(); }