Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -14501,333 +14501,340 @@ if (getLangOpts().Coroutines && FSI->isCoroutine()) CheckCompletedCoroutineBody(FD, Body); - // Do not call PopExpressionEvaluationContext() if it is a lambda because one - // is already popped when finishing the lambda in BuildLambdaExpr(). This is - // meant to pop the context added in ActOnStartOfFunctionDef(). - ExitFunctionBodyRAII ExitRAII(*this, isLambdaCallOperator(FD)); - - if (FD) { - FD->setBody(Body); - FD->setWillHaveBody(false); - - if (getLangOpts().CPlusPlus14) { - if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() && - FD->getReturnType()->isUndeducedType()) { - // If the function has a deduced result type but contains no 'return' - // statements, the result type as written must be exactly 'auto', and - // the deduced result type is 'void'. - if (!FD->getReturnType()->getAs()) { - Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto) - << FD->getReturnType(); - FD->setInvalidDecl(); - } else { - // Substitute 'void' for the 'auto' in the type. - TypeLoc ResultType = getReturnTypeLoc(FD); - Context.adjustDeducedFunctionResultType( - FD, SubstAutoType(ResultType.getType(), Context.VoidTy)); + { + // Do not call PopExpressionEvaluationContext() if it is a lambda because + // one is already popped when finishing the lambda in BuildLambdaExpr(). + // This is meant to pop the context added in ActOnStartOfFunctionDef(). + ExitFunctionBodyRAII ExitRAII(*this, isLambdaCallOperator(FD)); + + if (FD) { + FD->setBody(Body); + FD->setWillHaveBody(false); + + if (getLangOpts().CPlusPlus14) { + if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() && + FD->getReturnType()->isUndeducedType()) { + // If the function has a deduced result type but contains no 'return' + // statements, the result type as written must be exactly 'auto', and + // the deduced result type is 'void'. + if (!FD->getReturnType()->getAs()) { + Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto) + << FD->getReturnType(); + FD->setInvalidDecl(); + } else { + // Substitute 'void' for the 'auto' in the type. + TypeLoc ResultType = getReturnTypeLoc(FD); + Context.adjustDeducedFunctionResultType( + FD, SubstAutoType(ResultType.getType(), Context.VoidTy)); + } + } + } else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) { + // In C++11, we don't use 'auto' deduction rules for lambda call + // operators because we don't support return type deduction. + auto *LSI = getCurLambda(); + if (LSI->HasImplicitReturnType) { + deduceClosureReturnType(*LSI); + + // C++11 [expr.prim.lambda]p4: + // [...] if there are no return statements in the compound-statement + // [the deduced type is] the type void + QualType RetType = + LSI->ReturnType.isNull() ? Context.VoidTy : LSI->ReturnType; + + // Update the return type to the deduced type. + const auto *Proto = FD->getType()->castAs(); + FD->setType(Context.getFunctionType(RetType, Proto->getParamTypes(), + Proto->getExtProtoInfo())); } } - } else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) { - // In C++11, we don't use 'auto' deduction rules for lambda call - // operators because we don't support return type deduction. - auto *LSI = getCurLambda(); - if (LSI->HasImplicitReturnType) { - deduceClosureReturnType(*LSI); - - // C++11 [expr.prim.lambda]p4: - // [...] if there are no return statements in the compound-statement - // [the deduced type is] the type void - QualType RetType = - LSI->ReturnType.isNull() ? Context.VoidTy : LSI->ReturnType; - - // Update the return type to the deduced type. - const auto *Proto = FD->getType()->castAs(); - FD->setType(Context.getFunctionType(RetType, Proto->getParamTypes(), - Proto->getExtProtoInfo())); + + // If the function implicitly returns zero (like 'main') or is naked, + // don't complain about missing return statements. + if (FD->hasImplicitReturnZero() || FD->hasAttr()) + WP.disableCheckFallThrough(); + + // MSVC permits the use of pure specifier (=0) on function definition, + // defined at class scope, warn about this non-standard construct. + if (getLangOpts().MicrosoftExt && FD->isPure() && !FD->isOutOfLine()) + Diag(FD->getLocation(), diag::ext_pure_function_definition); + + if (!FD->isInvalidDecl()) { + // Don't diagnose unused parameters of defaulted or deleted functions. + if (!FD->isDeleted() && !FD->isDefaulted() && !FD->hasSkippedBody()) + DiagnoseUnusedParameters(FD->parameters()); + DiagnoseSizeOfParametersAndReturnValue(FD->parameters(), + FD->getReturnType(), FD); + + // If this is a structor, we need a vtable. + if (CXXConstructorDecl *Constructor = dyn_cast(FD)) + MarkVTableUsed(FD->getLocation(), Constructor->getParent()); + else if (CXXDestructorDecl *Destructor = + dyn_cast(FD)) + MarkVTableUsed(FD->getLocation(), Destructor->getParent()); + + // Try to apply the named return value optimization. We have to check + // if we can do this here because lambdas keep return statements around + // to deduce an implicit return type. + if (FD->getReturnType()->isRecordType() && + (!getLangOpts().CPlusPlus || !FD->isDependentContext())) + computeNRVO(Body, FSI); } - } - // If the function implicitly returns zero (like 'main') or is naked, - // don't complain about missing return statements. - if (FD->hasImplicitReturnZero() || FD->hasAttr()) - WP.disableCheckFallThrough(); - - // MSVC permits the use of pure specifier (=0) on function definition, - // defined at class scope, warn about this non-standard construct. - if (getLangOpts().MicrosoftExt && FD->isPure() && !FD->isOutOfLine()) - Diag(FD->getLocation(), diag::ext_pure_function_definition); - - if (!FD->isInvalidDecl()) { - // Don't diagnose unused parameters of defaulted or deleted functions. - if (!FD->isDeleted() && !FD->isDefaulted() && !FD->hasSkippedBody()) - DiagnoseUnusedParameters(FD->parameters()); - DiagnoseSizeOfParametersAndReturnValue(FD->parameters(), - FD->getReturnType(), FD); - - // If this is a structor, we need a vtable. - if (CXXConstructorDecl *Constructor = dyn_cast(FD)) - MarkVTableUsed(FD->getLocation(), Constructor->getParent()); - else if (CXXDestructorDecl *Destructor = dyn_cast(FD)) - MarkVTableUsed(FD->getLocation(), Destructor->getParent()); - - // Try to apply the named return value optimization. We have to check - // if we can do this here because lambdas keep return statements around - // to deduce an implicit return type. - if (FD->getReturnType()->isRecordType() && - (!getLangOpts().CPlusPlus || !FD->isDependentContext())) - computeNRVO(Body, FSI); - } - - // GNU warning -Wmissing-prototypes: - // Warn if a global function is defined without a previous - // prototype declaration. This warning is issued even if the - // definition itself provides a prototype. The aim is to detect - // global functions that fail to be declared in header files. - const FunctionDecl *PossiblePrototype = nullptr; - if (ShouldWarnAboutMissingPrototype(FD, PossiblePrototype)) { - Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; - - if (PossiblePrototype) { - // We found a declaration that is not a prototype, - // but that could be a zero-parameter prototype - if (TypeSourceInfo *TI = PossiblePrototype->getTypeSourceInfo()) { - TypeLoc TL = TI->getTypeLoc(); - if (FunctionNoProtoTypeLoc FTL = TL.getAs()) - Diag(PossiblePrototype->getLocation(), - diag::note_declaration_not_a_prototype) - << (FD->getNumParams() != 0) - << (FD->getNumParams() == 0 - ? FixItHint::CreateInsertion(FTL.getRParenLoc(), "void") - : FixItHint{}); - } - } else { - // Returns true if the token beginning at this Loc is `const`. - auto isLocAtConst = [&](SourceLocation Loc, const SourceManager &SM, - const LangOptions &LangOpts) { - std::pair LocInfo = SM.getDecomposedLoc(Loc); - if (LocInfo.first.isInvalid()) - return false; + // GNU warning -Wmissing-prototypes: + // Warn if a global function is defined without a previous + // prototype declaration. This warning is issued even if the + // definition itself provides a prototype. The aim is to detect + // global functions that fail to be declared in header files. + const FunctionDecl *PossiblePrototype = nullptr; + if (ShouldWarnAboutMissingPrototype(FD, PossiblePrototype)) { + Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; + + if (PossiblePrototype) { + // We found a declaration that is not a prototype, + // but that could be a zero-parameter prototype + if (TypeSourceInfo *TI = PossiblePrototype->getTypeSourceInfo()) { + TypeLoc TL = TI->getTypeLoc(); + if (FunctionNoProtoTypeLoc FTL = TL.getAs()) + Diag(PossiblePrototype->getLocation(), + diag::note_declaration_not_a_prototype) + << (FD->getNumParams() != 0) + << (FD->getNumParams() == 0 ? FixItHint::CreateInsertion( + FTL.getRParenLoc(), "void") + : FixItHint{}); + } + } else { + // Returns true if the token beginning at this Loc is `const`. + auto isLocAtConst = [&](SourceLocation Loc, const SourceManager &SM, + const LangOptions &LangOpts) { + std::pair LocInfo = SM.getDecomposedLoc(Loc); + if (LocInfo.first.isInvalid()) + return false; - bool Invalid = false; - StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); - if (Invalid) - return false; + bool Invalid = false; + StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return false; - if (LocInfo.second > Buffer.size()) - return false; + if (LocInfo.second > Buffer.size()) + return false; - const char *LexStart = Buffer.data() + LocInfo.second; - StringRef StartTok(LexStart, Buffer.size() - LocInfo.second); + const char *LexStart = Buffer.data() + LocInfo.second; + StringRef StartTok(LexStart, Buffer.size() - LocInfo.second); - return StartTok.consume_front("const") && - (StartTok.empty() || isWhitespace(StartTok[0]) || - StartTok.startswith("/*") || StartTok.startswith("//")); - }; + return StartTok.consume_front("const") && + (StartTok.empty() || isWhitespace(StartTok[0]) || + StartTok.startswith("/*") || StartTok.startswith("//")); + }; - auto findBeginLoc = [&]() { - // If the return type has `const` qualifier, we want to insert - // `static` before `const` (and not before the typename). - if ((FD->getReturnType()->isAnyPointerType() && - FD->getReturnType()->getPointeeType().isConstQualified()) || - FD->getReturnType().isConstQualified()) { - // But only do this if we can determine where the `const` is. + auto findBeginLoc = [&]() { + // If the return type has `const` qualifier, we want to insert + // `static` before `const` (and not before the typename). + if ((FD->getReturnType()->isAnyPointerType() && + FD->getReturnType()->getPointeeType().isConstQualified()) || + FD->getReturnType().isConstQualified()) { + // But only do this if we can determine where the `const` is. - if (isLocAtConst(FD->getBeginLoc(), getSourceManager(), - getLangOpts())) + if (isLocAtConst(FD->getBeginLoc(), getSourceManager(), + getLangOpts())) - return FD->getBeginLoc(); - } - return FD->getTypeSpecStartLoc(); - }; - Diag(FD->getTypeSpecStartLoc(), diag::note_static_for_internal_linkage) - << /* function */ 1 - << (FD->getStorageClass() == SC_None - ? FixItHint::CreateInsertion(findBeginLoc(), "static ") - : FixItHint{}); - } + return FD->getBeginLoc(); + } + return FD->getTypeSpecStartLoc(); + }; + Diag(FD->getTypeSpecStartLoc(), + diag::note_static_for_internal_linkage) + << /* function */ 1 + << (FD->getStorageClass() == SC_None + ? FixItHint::CreateInsertion(findBeginLoc(), "static ") + : FixItHint{}); + } - // GNU warning -Wstrict-prototypes - // Warn if K&R function is defined without a previous declaration. - // This warning is issued only if the definition itself does not provide - // a prototype. Only K&R definitions do not provide a prototype. - if (!FD->hasWrittenPrototype()) { - TypeSourceInfo *TI = FD->getTypeSourceInfo(); - TypeLoc TL = TI->getTypeLoc(); - FunctionTypeLoc FTL = TL.getAsAdjusted(); - Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 2; + // GNU warning -Wstrict-prototypes + // Warn if K&R function is defined without a previous declaration. + // This warning is issued only if the definition itself does not + // provide a prototype. Only K&R definitions do not provide a + // prototype. + if (!FD->hasWrittenPrototype()) { + TypeSourceInfo *TI = FD->getTypeSourceInfo(); + TypeLoc TL = TI->getTypeLoc(); + FunctionTypeLoc FTL = TL.getAsAdjusted(); + Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 2; + } } - } - // Warn on CPUDispatch with an actual body. - if (FD->isMultiVersion() && FD->hasAttr() && Body) - if (const auto *CmpndBody = dyn_cast(Body)) - if (!CmpndBody->body_empty()) - Diag(CmpndBody->body_front()->getBeginLoc(), - diag::warn_dispatch_body_ignored); - - if (auto *MD = dyn_cast(FD)) { - const CXXMethodDecl *KeyFunction; - if (MD->isOutOfLine() && (MD = MD->getCanonicalDecl()) && - MD->isVirtual() && - (KeyFunction = Context.getCurrentKeyFunction(MD->getParent())) && - MD == KeyFunction->getCanonicalDecl()) { - // Update the key-function state if necessary for this ABI. - if (FD->isInlined() && - !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { - Context.setNonKeyFunction(MD); - - // If the newly-chosen key function is already defined, then we - // need to mark the vtable as used retroactively. - KeyFunction = Context.getCurrentKeyFunction(MD->getParent()); - const FunctionDecl *Definition; - if (KeyFunction && KeyFunction->isDefined(Definition)) - MarkVTableUsed(Definition->getLocation(), MD->getParent(), true); - } else { - // We just defined they key function; mark the vtable as used. - MarkVTableUsed(FD->getLocation(), MD->getParent(), true); + // Warn on CPUDispatch with an actual body. + if (FD->isMultiVersion() && FD->hasAttr() && Body) + if (const auto *CmpndBody = dyn_cast(Body)) + if (!CmpndBody->body_empty()) + Diag(CmpndBody->body_front()->getBeginLoc(), + diag::warn_dispatch_body_ignored); + + if (auto *MD = dyn_cast(FD)) { + const CXXMethodDecl *KeyFunction; + if (MD->isOutOfLine() && (MD = MD->getCanonicalDecl()) && + MD->isVirtual() && + (KeyFunction = Context.getCurrentKeyFunction(MD->getParent())) && + MD == KeyFunction->getCanonicalDecl()) { + // Update the key-function state if necessary for this ABI. + if (FD->isInlined() && + !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { + Context.setNonKeyFunction(MD); + + // If the newly-chosen key function is already defined, then we + // need to mark the vtable as used retroactively. + KeyFunction = Context.getCurrentKeyFunction(MD->getParent()); + const FunctionDecl *Definition; + if (KeyFunction && KeyFunction->isDefined(Definition)) + MarkVTableUsed(Definition->getLocation(), MD->getParent(), true); + } else { + // We just defined they key function; mark the vtable as used. + MarkVTableUsed(FD->getLocation(), MD->getParent(), true); + } } } - } - assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) && - "Function parsing confused"); - } else if (ObjCMethodDecl *MD = dyn_cast_or_null(dcl)) { - assert(MD == getCurMethodDecl() && "Method parsing confused"); - MD->setBody(Body); - if (!MD->isInvalidDecl()) { - DiagnoseSizeOfParametersAndReturnValue(MD->parameters(), - MD->getReturnType(), MD); - - if (Body) - computeNRVO(Body, FSI); - } - if (FSI->ObjCShouldCallSuper) { - Diag(MD->getEndLoc(), diag::warn_objc_missing_super_call) - << MD->getSelector().getAsString(); - FSI->ObjCShouldCallSuper = false; - } - if (FSI->ObjCWarnForNoDesignatedInitChain) { - const ObjCMethodDecl *InitMethod = nullptr; - bool isDesignated = - MD->isDesignatedInitializerForTheInterface(&InitMethod); - assert(isDesignated && InitMethod); - (void)isDesignated; - - auto superIsNSObject = [&](const ObjCMethodDecl *MD) { - auto IFace = MD->getClassInterface(); - if (!IFace) - return false; - auto SuperD = IFace->getSuperClass(); - if (!SuperD) - return false; - return SuperD->getIdentifier() == - NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject); - }; - // Don't issue this warning for unavailable inits or direct subclasses - // of NSObject. - if (!MD->isUnavailable() && !superIsNSObject(MD)) { - Diag(MD->getLocation(), - diag::warn_objc_designated_init_missing_super_call); - Diag(InitMethod->getLocation(), - diag::note_objc_designated_init_marked_here); + assert( + (FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) && + "Function parsing confused"); + } else if (ObjCMethodDecl *MD = dyn_cast_or_null(dcl)) { + assert(MD == getCurMethodDecl() && "Method parsing confused"); + MD->setBody(Body); + if (!MD->isInvalidDecl()) { + DiagnoseSizeOfParametersAndReturnValue(MD->parameters(), + MD->getReturnType(), MD); + + if (Body) + computeNRVO(Body, FSI); + } + if (FSI->ObjCShouldCallSuper) { + Diag(MD->getEndLoc(), diag::warn_objc_missing_super_call) + << MD->getSelector().getAsString(); + FSI->ObjCShouldCallSuper = false; + } + if (FSI->ObjCWarnForNoDesignatedInitChain) { + const ObjCMethodDecl *InitMethod = nullptr; + bool isDesignated = + MD->isDesignatedInitializerForTheInterface(&InitMethod); + assert(isDesignated && InitMethod); + (void)isDesignated; + + auto superIsNSObject = [&](const ObjCMethodDecl *MD) { + auto IFace = MD->getClassInterface(); + if (!IFace) + return false; + auto SuperD = IFace->getSuperClass(); + if (!SuperD) + return false; + return SuperD->getIdentifier() == + NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject); + }; + // Don't issue this warning for unavailable inits or direct subclasses + // of NSObject. + if (!MD->isUnavailable() && !superIsNSObject(MD)) { + Diag(MD->getLocation(), + diag::warn_objc_designated_init_missing_super_call); + Diag(InitMethod->getLocation(), + diag::note_objc_designated_init_marked_here); + } + FSI->ObjCWarnForNoDesignatedInitChain = false; + } + if (FSI->ObjCWarnForNoInitDelegation) { + // Don't issue this warning for unavaialable inits. + if (!MD->isUnavailable()) + Diag(MD->getLocation(), + diag::warn_objc_secondary_init_missing_init_call); + FSI->ObjCWarnForNoInitDelegation = false; } - FSI->ObjCWarnForNoDesignatedInitChain = false; - } - if (FSI->ObjCWarnForNoInitDelegation) { - // Don't issue this warning for unavaialable inits. - if (!MD->isUnavailable()) - Diag(MD->getLocation(), - diag::warn_objc_secondary_init_missing_init_call); - FSI->ObjCWarnForNoInitDelegation = false; - } - diagnoseImplicitlyRetainedSelf(*this); - } else { - // Parsing the function declaration failed in some way. Pop the fake scope - // we pushed on. - PopFunctionScopeInfo(ActivePolicy, dcl); - return nullptr; - } + diagnoseImplicitlyRetainedSelf(*this); + } else { + // Parsing the function declaration failed in some way. Pop the fake scope + // we pushed on. + PopFunctionScopeInfo(ActivePolicy, dcl); + return nullptr; + } - if (Body && FSI->HasPotentialAvailabilityViolations) - DiagnoseUnguardedAvailabilityViolations(dcl); + if (Body && FSI->HasPotentialAvailabilityViolations) + DiagnoseUnguardedAvailabilityViolations(dcl); - assert(!FSI->ObjCShouldCallSuper && - "This should only be set for ObjC methods, which should have been " - "handled in the block above."); + assert(!FSI->ObjCShouldCallSuper && + "This should only be set for ObjC methods, which should have been " + "handled in the block above."); - // Verify and clean out per-function state. - if (Body && (!FD || !FD->isDefaulted())) { - // C++ constructors that have function-try-blocks can't have return - // statements in the handlers of that block. (C++ [except.handle]p14) - // Verify this. - if (FD && isa(FD) && isa(Body)) - DiagnoseReturnInConstructorExceptionHandler(cast(Body)); + // Verify and clean out per-function state. + if (Body && (!FD || !FD->isDefaulted())) { + // C++ constructors that have function-try-blocks can't have return + // statements in the handlers of that block. (C++ [except.handle]p14) + // Verify this. + if (FD && isa(FD) && isa(Body)) + DiagnoseReturnInConstructorExceptionHandler(cast(Body)); - // Verify that gotos and switch cases don't jump into scopes illegally. - if (FSI->NeedsScopeChecking() && - !PP.isCodeCompletionEnabled()) - DiagnoseInvalidJumps(Body); + // Verify that gotos and switch cases don't jump into scopes illegally. + if (FSI->NeedsScopeChecking() && !PP.isCodeCompletionEnabled()) + DiagnoseInvalidJumps(Body); - if (CXXDestructorDecl *Destructor = dyn_cast(dcl)) { - if (!Destructor->getParent()->isDependentType()) - CheckDestructor(Destructor); + if (CXXDestructorDecl *Destructor = dyn_cast(dcl)) { + if (!Destructor->getParent()->isDependentType()) + CheckDestructor(Destructor); - MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), - Destructor->getParent()); - } + MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), + Destructor->getParent()); + } - // If any errors have occurred, clear out any temporaries that may have - // been leftover. This ensures that these temporaries won't be picked up for - // deletion in some later function. - if (hasUncompilableErrorOccurred() || - getDiagnostics().getSuppressAllDiagnostics()) { - DiscardCleanupsInEvaluationContext(); - } - if (!hasUncompilableErrorOccurred() && - !isa(dcl)) { - // Since the body is valid, issue any analysis-based warnings that are - // enabled. - ActivePolicy = &WP; - } + // If any errors have occurred, clear out any temporaries that may have + // been leftover. This ensures that these temporaries won't be picked up + // for deletion in some later function. + if (hasUncompilableErrorOccurred() || + getDiagnostics().getSuppressAllDiagnostics()) { + DiscardCleanupsInEvaluationContext(); + } + if (!hasUncompilableErrorOccurred() && !isa(dcl)) { + // Since the body is valid, issue any analysis-based warnings that are + // enabled. + ActivePolicy = &WP; + } - if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() && - !CheckConstexprFunctionDefinition(FD, CheckConstexprKind::Diagnose)) - FD->setInvalidDecl(); + if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() && + !CheckConstexprFunctionDefinition(FD, CheckConstexprKind::Diagnose)) + FD->setInvalidDecl(); - if (FD && FD->hasAttr()) { - for (const Stmt *S : Body->children()) { - // Allow local register variables without initializer as they don't - // require prologue. - bool RegisterVariables = false; - if (auto *DS = dyn_cast(S)) { - for (const auto *Decl : DS->decls()) { - if (const auto *Var = dyn_cast(Decl)) { - RegisterVariables = - Var->hasAttr() && !Var->hasInit(); - if (!RegisterVariables) - break; + if (FD && FD->hasAttr()) { + for (const Stmt *S : Body->children()) { + // Allow local register variables without initializer as they don't + // require prologue. + bool RegisterVariables = false; + if (auto *DS = dyn_cast(S)) { + for (const auto *Decl : DS->decls()) { + if (const auto *Var = dyn_cast(Decl)) { + RegisterVariables = + Var->hasAttr() && !Var->hasInit(); + if (!RegisterVariables) + break; + } } } - } - if (RegisterVariables) - continue; - if (!isa(S) && !isa(S)) { - Diag(S->getBeginLoc(), diag::err_non_asm_stmt_in_naked_function); - Diag(FD->getAttr()->getLocation(), diag::note_attribute); - FD->setInvalidDecl(); - break; + if (RegisterVariables) + continue; + if (!isa(S) && !isa(S)) { + Diag(S->getBeginLoc(), diag::err_non_asm_stmt_in_naked_function); + Diag(FD->getAttr()->getLocation(), diag::note_attribute); + FD->setInvalidDecl(); + break; + } } } - } - assert(ExprCleanupObjects.size() == - ExprEvalContexts.back().NumCleanupObjects && - "Leftover temporaries in function"); - assert(!Cleanup.exprNeedsCleanups() && "Unaccounted cleanups in function"); - assert(MaybeODRUseExprs.empty() && - "Leftover expressions for odr-use checking"); - } + assert(ExprCleanupObjects.size() == + ExprEvalContexts.back().NumCleanupObjects && + "Leftover temporaries in function"); + assert(!Cleanup.exprNeedsCleanups() && + "Unaccounted cleanups in function"); + assert(MaybeODRUseExprs.empty() && + "Leftover expressions for odr-use checking"); + } + } // Pops the ExitFunctionBodyRAII scope, which needs to happen before we pop + // the declaration context below. Otherwise, we're unable to transform + // 'this' expressions when transforming immediate context functions. if (!IsInstantiation) PopDeclContext(); Index: clang/test/SemaCXX/cxx2a-consteval.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-consteval.cpp +++ clang/test/SemaCXX/cxx2a-consteval.cpp @@ -612,3 +612,23 @@ static_assert(is_same::value); } // namespace unevaluated + +namespace PR48235 { +consteval int d() { + return 1; +} + +struct A { + consteval int a() const { return 1; } + + void b() { + this->a() + d(); // expected-error {{call to consteval function 'PR48235::A::a' is not a constant expression}} \ + // expected-note {{use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function}} + } + + void c() { + a() + d(); // expected-error {{call to consteval function 'PR48235::A::a' is not a constant expression}} \ + // expected-note {{use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function}} + } +}; +} // PR48235