diff options
Diffstat (limited to 'lib/Sema/Sema.cpp')
-rw-r--r-- | lib/Sema/Sema.cpp | 185 |
1 files changed, 157 insertions, 28 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index a18f71422fde..4e57e5ef81c6 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -70,6 +70,49 @@ void Sema::ActOnTranslationUnitScope(Scope *S) { PushDeclContext(S, Context.getTranslationUnitDecl()); } +namespace clang { +namespace sema { + +class SemaPPCallbacks : public PPCallbacks { + Sema *S = nullptr; + llvm::SmallVector<SourceLocation, 8> IncludeStack; + +public: + void set(Sema &S) { this->S = &S; } + + void reset() { S = nullptr; } + + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) override { + if (!S) + return; + switch (Reason) { + case EnterFile: { + SourceManager &SM = S->getSourceManager(); + SourceLocation IncludeLoc = SM.getIncludeLoc(SM.getFileID(Loc)); + if (IncludeLoc.isValid()) { + IncludeStack.push_back(IncludeLoc); + S->DiagnoseNonDefaultPragmaPack( + Sema::PragmaPackDiagnoseKind::NonDefaultStateAtInclude, IncludeLoc); + } + break; + } + case ExitFile: + if (!IncludeStack.empty()) + S->DiagnoseNonDefaultPragmaPack( + Sema::PragmaPackDiagnoseKind::ChangedStateAtExit, + IncludeStack.pop_back_val()); + break; + default: + break; + } + } +}; + +} // end namespace sema +} // end namespace clang + Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) : ExternalSource(nullptr), isMultiplexExternalSource(false), @@ -122,6 +165,12 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, // Initilization of data sharing attributes stack for OpenMP InitDataSharingAttributesStack(); + + std::unique_ptr<sema::SemaPPCallbacks> Callbacks = + llvm::make_unique<sema::SemaPPCallbacks>(); + SemaPPCallbackHandler = Callbacks.get(); + PP.addPPCallbacks(std::move(Callbacks)); + SemaPPCallbackHandler->set(*this); } void Sema::addImplicitTypedef(StringRef Name, QualType T) { @@ -306,6 +355,10 @@ Sema::~Sema() { // Destroys data sharing attributes stack for OpenMP DestroyDataSharingAttributesStack(); + // Detach from the PP callback handler which outlives Sema since it's owned + // by the preprocessor. + SemaPPCallbackHandler->reset(); + assert(DelayedTypos.empty() && "Uncorrected typos!"); } @@ -383,14 +436,26 @@ void Sema::diagnoseNullableToNonnullConversion(QualType DstType, } void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) { - if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer) - return; - if (E->getType()->isNullPtrType()) + if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant, + E->getLocStart())) return; // nullptr only exists from C++11 on, so don't warn on its absence earlier. if (!getLangOpts().CPlusPlus11) return; + if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer) + return; + if (E->IgnoreParenImpCasts()->getType()->isNullPtrType()) + return; + + // If it is a macro from system header, and if the macro name is not "NULL", + // do not warn. + SourceLocation MaybeMacroLoc = E->getLocStart(); + if (Diags.getSuppressSystemWarnings() && + SourceMgr.isInSystemMacro(MaybeMacroLoc) && + !findMacroSpelling(MaybeMacroLoc, "NULL")) + return; + Diag(E->getLocStart(), diag::warn_zero_as_null_pointer_constant) << FixItHint::CreateReplacement(E->getSourceRange(), "nullptr"); } @@ -464,7 +529,7 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { case Type::STK_IntegralComplex: return CK_IntegralComplexToBoolean; case Type::STK_FloatingComplex: return CK_FloatingComplexToBoolean; } - return CK_Invalid; + llvm_unreachable("unknown scalar type kind"); } /// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector. @@ -529,6 +594,23 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { return false; } +static bool isFunctionOrVarDeclExternC(NamedDecl *ND) { + if (auto *FD = dyn_cast<FunctionDecl>(ND)) + return FD->isExternC(); + return cast<VarDecl>(ND)->isExternC(); +} + +/// Determine whether ND is an external-linkage function or variable whose +/// type has no linkage. +bool Sema::isExternalWithNoLinkageType(ValueDecl *VD) { + // Note: it's not quite enough to check whether VD has UniqueExternalLinkage, + // because we also want to catch the case where its type has VisibleNoLinkage, + // which does not affect the linkage of VD. + return getLangOpts().CPlusPlus && VD->hasExternalFormalLinkage() && + !isExternalFormalLinkage(VD->getType()->getLinkage()) && + !isFunctionOrVarDeclExternC(VD); +} + /// Obtains a sorted list of functions and variables that are undefined but /// ODR-used. void Sema::getUndefinedButUsed( @@ -545,17 +627,27 @@ void Sema::getUndefinedButUsed( if (isa<CXXDeductionGuideDecl>(ND)) continue; + if (ND->hasAttr<DLLImportAttr>() || ND->hasAttr<DLLExportAttr>()) { + // An exported function will always be emitted when defined, so even if + // the function is inline, it doesn't have to be emitted in this TU. An + // imported function implies that it has been exported somewhere else. + continue; + } + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { if (FD->isDefined()) continue; if (FD->isExternallyVisible() && + !isExternalWithNoLinkageType(FD) && !FD->getMostRecentDecl()->isInlined()) continue; } else { auto *VD = cast<VarDecl>(ND); if (VD->hasDefinition() != VarDecl::DeclarationOnly) continue; - if (VD->isExternallyVisible() && !VD->getMostRecentDecl()->isInline()) + if (VD->isExternallyVisible() && + !isExternalWithNoLinkageType(VD) && + !VD->getMostRecentDecl()->isInline()) continue; } @@ -573,33 +665,43 @@ static void checkUndefinedButUsed(Sema &S) { S.getUndefinedButUsed(Undefined); if (Undefined.empty()) return; - for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator - I = Undefined.begin(), E = Undefined.end(); I != E; ++I) { - NamedDecl *ND = I->first; - - if (ND->hasAttr<DLLImportAttr>() || ND->hasAttr<DLLExportAttr>()) { - // An exported function will always be emitted when defined, so even if - // the function is inline, it doesn't have to be emitted in this TU. An - // imported function implies that it has been exported somewhere else. - continue; - } - - if (!ND->isExternallyVisible()) { - S.Diag(ND->getLocation(), diag::warn_undefined_internal) - << isa<VarDecl>(ND) << ND; - } else if (auto *FD = dyn_cast<FunctionDecl>(ND)) { + for (auto Undef : Undefined) { + ValueDecl *VD = cast<ValueDecl>(Undef.first); + SourceLocation UseLoc = Undef.second; + + if (S.isExternalWithNoLinkageType(VD)) { + // C++ [basic.link]p8: + // A type without linkage shall not be used as the type of a variable + // or function with external linkage unless + // -- the entity has C language linkage + // -- the entity is not odr-used or is defined in the same TU + // + // As an extension, accept this in cases where the type is externally + // visible, since the function or variable actually can be defined in + // another translation unit in that case. + S.Diag(VD->getLocation(), isExternallyVisible(VD->getType()->getLinkage()) + ? diag::ext_undefined_internal_type + : diag::err_undefined_internal_type) + << isa<VarDecl>(VD) << VD; + } else if (!VD->isExternallyVisible()) { + // FIXME: We can promote this to an error. The function or variable can't + // be defined anywhere else, so the program must necessarily violate the + // one definition rule. + S.Diag(VD->getLocation(), diag::warn_undefined_internal) + << isa<VarDecl>(VD) << VD; + } else if (auto *FD = dyn_cast<FunctionDecl>(VD)) { (void)FD; assert(FD->getMostRecentDecl()->isInlined() && "used object requires definition but isn't inline or internal?"); // FIXME: This is ill-formed; we should reject. - S.Diag(ND->getLocation(), diag::warn_undefined_inline) << ND; + S.Diag(VD->getLocation(), diag::warn_undefined_inline) << VD; } else { - assert(cast<VarDecl>(ND)->getMostRecentDecl()->isInline() && + assert(cast<VarDecl>(VD)->getMostRecentDecl()->isInline() && "used var requires definition but isn't inline or internal?"); - S.Diag(ND->getLocation(), diag::err_undefined_inline_var) << ND; + S.Diag(VD->getLocation(), diag::err_undefined_inline_var) << VD; } - if (I->second.isValid()) - S.Diag(I->second, diag::note_used_here); + if (UseLoc.isValid()) + S.Diag(UseLoc, diag::note_used_here); } S.UndefinedButUsed.clear(); @@ -635,7 +737,8 @@ static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD, E = RD->decls_end(); I != E && Complete; ++I) { if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) - Complete = M->isDefined() || (M->isPure() && !isa<CXXDestructorDecl>(M)); + Complete = M->isDefined() || M->isDefaulted() || + (M->isPure() && !isa<CXXDestructorDecl>(M)); else if (const FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(*I)) // If the template function is marked as late template parsed at this // point, it has not been instantiated and therefore we have not @@ -713,10 +816,24 @@ void Sema::emitAndClearUnusedLocalTypedefWarnings() { /// declarations. void Sema::ActOnStartOfTranslationUnit() { if (getLangOpts().ModulesTS) { + SourceLocation StartOfTU = + SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); + // We start in the global module; all those declarations are implicitly // module-private (though they do not have module linkage). - Context.getTranslationUnitDecl()->setModuleOwnershipKind( - Decl::ModuleOwnershipKind::ModulePrivate); + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + auto *GlobalModule = Map.createGlobalModuleForInterfaceUnit(StartOfTU); + assert(GlobalModule && "module creation should not fail"); + + // Enter the scope of the global module. + ModuleScopes.push_back({}); + ModuleScopes.back().Module = GlobalModule; + VisibleModules.setVisible(GlobalModule, StartOfTU); + + // All declarations created from now on are owned by the global module. + auto *TU = Context.getTranslationUnitDecl(); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); + TU->setLocalOwningModule(GlobalModule); } } @@ -769,6 +886,7 @@ void Sema::ActOnEndOfTranslationUnit() { CheckDelayedMemberExceptionSpecs(); } + DiagnoseUnterminatedPragmaPack(); DiagnoseUnterminatedPragmaAttribute(); // All delayed member exception specs should be checked or we end up accepting @@ -825,6 +943,17 @@ void Sema::ActOnEndOfTranslationUnit() { } if (TUKind == TU_Module) { + // If we are building a module interface unit, we need to have seen the + // module declaration by now. + if (getLangOpts().getCompilingModule() == + LangOptions::CMK_ModuleInterface && + ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) { + // FIXME: Make a better guess as to where to put the module declaration. + Diag(getSourceManager().getLocForStartOfFile( + getSourceManager().getMainFileID()), + diag::err_module_declaration_missing); + } + // If we are building a module, resolve all of the exported declarations // now. if (Module *CurrentModule = PP.getCurrentModule()) { |