diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 32 | ||||
-rw-r--r-- | lib/Sema/SemaCast.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 94 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 259 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 242 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 29 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 40 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 52 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 54 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 196 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 5 |
16 files changed, 851 insertions, 192 deletions
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 7a5973299f914..7d9ae621c93d6 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS ) if (MSVC) + set_source_files_properties(SemaDeclAttr.cpp PROPERTIES COMPILE_FLAGS /bigobj) set_source_files_properties(SemaExpr.cpp PROPERTIES COMPILE_FLAGS /bigobj) endif() diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 2f493fa5fbef8..ca1d27e9505f0 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -477,6 +477,13 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { return true; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // If this is a function template and none of its specializations is used, + // we should warn. + if (FunctionTemplateDecl *Template = FD->getDescribedFunctionTemplate()) + for (const auto *Spec : Template->specializations()) + if (ShouldRemoveFromUnused(SemaRef, Spec)) + return true; + // UnusedFileScopedDecls stores the first declaration. // The declaration may have become definition so check again. const FunctionDecl *DeclToCheck; @@ -500,6 +507,13 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { VD->isUsableInConstantExpressions(SemaRef->Context)) return true; + if (VarTemplateDecl *Template = VD->getDescribedVarTemplate()) + // If this is a variable template and none of its specializations is used, + // we should warn. + for (const auto *Spec : Template->specializations()) + if (ShouldRemoveFromUnused(SemaRef, Spec)) + return true; + // UnusedFileScopedDecls stores the first declaration. // The declaration may have become definition so check again. const VarDecl *DeclToCheck = VD->getDefinition(); @@ -905,10 +919,14 @@ void Sema::ActOnEndOfTranslationUnit() { << /*function*/0 << DiagD->getDeclName(); } } else { - Diag(DiagD->getLocation(), - isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function - : diag::warn_unused_function) - << DiagD->getDeclName(); + if (FD->getDescribedFunctionTemplate()) + Diag(DiagD->getLocation(), diag::warn_unused_template) + << /*function*/0 << DiagD->getDeclName(); + else + Diag(DiagD->getLocation(), + isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function + : diag::warn_unused_function) + << DiagD->getDeclName(); } } else { const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition(); @@ -924,7 +942,11 @@ void Sema::ActOnEndOfTranslationUnit() { Diag(DiagD->getLocation(), diag::warn_unused_const_variable) << DiagD->getDeclName(); } else { - Diag(DiagD->getLocation(), diag::warn_unused_variable) + if (DiagD->getDescribedVarTemplate()) + Diag(DiagD->getLocation(), diag::warn_unused_template) + << /*variable*/1 << DiagD->getDeclName(); + else + Diag(DiagD->getLocation(), diag::warn_unused_variable) << DiagD->getDeclName(); } } diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index 7e91709e67da8..7d534263f4681 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -1871,7 +1871,8 @@ static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType, // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization // preserves Result. Result = E; - if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(Result)) + if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate( + Result, /*DoFunctionPointerConversion=*/true)) return false; return Result.isUsable(); } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index cfac3f1dc1de9..8fb2f41392365 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -3869,6 +3869,41 @@ static void AddObjCProperties( } } +static void AddRecordMembersCompletionResults(Sema &SemaRef, + ResultBuilder &Results, Scope *S, + QualType BaseType, + RecordDecl *RD) { + // Indicate that we are performing a member access, and the cv-qualifiers + // for the base object type. + Results.setObjectTypeQualifiers(BaseType.getQualifiers()); + + // Access to a C/C++ class, struct, or union. + Results.allowNestedNameSpecifiers(); + CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext); + SemaRef.LookupVisibleDecls(RD, Sema::LookupMemberName, Consumer, + SemaRef.CodeCompleter->includeGlobals(), + /*IncludeDependentBases=*/true); + + if (SemaRef.getLangOpts().CPlusPlus) { + if (!Results.empty()) { + // The "template" keyword can follow "->" or "." in the grammar. + // However, we only want to suggest the template keyword if something + // is dependent. + bool IsDependent = BaseType->isDependentType(); + if (!IsDependent) { + for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent()) + if (DeclContext *Ctx = DepScope->getEntity()) { + IsDependent = Ctx->isDependentContext(); + break; + } + } + + if (IsDependent) + Results.AddResult(CodeCompletionResult("template")); + } + } +} + void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, SourceLocation OpLoc, bool IsArrow, bool IsBaseExprStatement) { @@ -3879,8 +3914,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, if (ConvertedBase.isInvalid()) return; Base = ConvertedBase.get(); - - typedef CodeCompletionResult Result; QualType BaseType = Base->getType(); @@ -3915,34 +3948,18 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, &ResultBuilder::IsMember); Results.EnterNewScope(); if (const RecordType *Record = BaseType->getAs<RecordType>()) { - // Indicate that we are performing a member access, and the cv-qualifiers - // for the base object type. - Results.setObjectTypeQualifiers(BaseType.getQualifiers()); - - // Access to a C/C++ class, struct, or union. - Results.allowNestedNameSpecifiers(); - CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer, - CodeCompleter->includeGlobals()); - - if (getLangOpts().CPlusPlus) { - if (!Results.empty()) { - // The "template" keyword can follow "->" or "." in the grammar. - // However, we only want to suggest the template keyword if something - // is dependent. - bool IsDependent = BaseType->isDependentType(); - if (!IsDependent) { - for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent()) - if (DeclContext *Ctx = DepScope->getEntity()) { - IsDependent = Ctx->isDependentContext(); - break; - } - } - - if (IsDependent) - Results.AddResult(Result("template")); - } - } + AddRecordMembersCompletionResults(*this, Results, S, BaseType, + Record->getDecl()); + } else if (const auto *TST = BaseType->getAs<TemplateSpecializationType>()) { + TemplateName TN = TST->getTemplateName(); + if (const auto *TD = + dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) { + CXXRecordDecl *RD = TD->getTemplatedDecl(); + AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD); + } + } else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) { + if (auto *RD = ICNT->getDecl()) + AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD); } else if (!IsArrow && BaseType->isObjCObjectPointerType()) { // Objective-C property reference. AddedPropertiesSet AddedProperties; @@ -7811,6 +7828,23 @@ void Sema::CodeCompleteNaturalLanguage() { nullptr, 0); } +void Sema::CodeCompleteAvailabilityPlatformName() { + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), + CodeCompletionContext::CCC_Other); + Results.EnterNewScope(); + static const char *Platforms[] = {"macOS", "iOS", "watchOS", "tvOS"}; + for (const char *Platform : llvm::makeArrayRef(Platforms)) { + Results.AddResult(CodeCompletionResult(Platform)); + Results.AddResult(CodeCompletionResult(Results.getAllocator().CopyString( + Twine(Platform) + "ApplicationExtension"))); + } + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, Results.data(), + Results.size()); +} + void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, SmallVectorImpl<CodeCompletionResult> &Results) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2612023f59db1..2e069a9defaa4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -64,22 +64,45 @@ namespace { class TypeNameValidatorCCC : public CorrectionCandidateCallback { public: - TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false, - bool AllowTemplates=false) - : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass), - AllowTemplates(AllowTemplates) { - WantExpressionKeywords = false; - WantCXXNamedCasts = false; - WantRemainingKeywords = false; + TypeNameValidatorCCC(bool AllowInvalid, bool WantClass = false, + bool AllowTemplates = false, + bool AllowNonTemplates = true) + : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass), + AllowTemplates(AllowTemplates), AllowNonTemplates(AllowNonTemplates) { + WantExpressionKeywords = false; + WantCXXNamedCasts = false; + WantRemainingKeywords = false; } bool ValidateCandidate(const TypoCorrection &candidate) override { if (NamedDecl *ND = candidate.getCorrectionDecl()) { + if (!AllowInvalidDecl && ND->isInvalidDecl()) + return false; + + if (getAsTypeTemplateDecl(ND)) + return AllowTemplates; + bool IsType = isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND); - bool AllowedTemplate = AllowTemplates && getAsTypeTemplateDecl(ND); - return (IsType || AllowedTemplate) && - (AllowInvalidDecl || !ND->isInvalidDecl()); + if (!IsType) + return false; + + if (AllowNonTemplates) + return true; + + // An injected-class-name of a class template (specialization) is valid + // as a template or as a non-template. + if (AllowTemplates) { + auto *RD = dyn_cast<CXXRecordDecl>(ND); + if (!RD || !RD->isInjectedClassName()) + return false; + RD = cast<CXXRecordDecl>(RD->getDeclContext()); + return RD->getDescribedClassTemplate() || + isa<ClassTemplateSpecializationDecl>(RD); + } + + return false; } + return !WantClassName && candidate.isKeyword(); } @@ -87,6 +110,7 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback { bool AllowInvalidDecl; bool WantClassName; bool AllowTemplates; + bool AllowNonTemplates; }; } // end anonymous namespace @@ -627,7 +651,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType, - bool AllowClassTemplates) { + bool IsTemplateName) { // Don't report typename errors for editor placeholders. if (II->isEditorPlaceholder()) return; @@ -639,28 +663,41 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS, llvm::make_unique<TypeNameValidatorCCC>( - false, false, AllowClassTemplates), + false, false, IsTemplateName, !IsTemplateName), CTK_ErrorRecovery)) { + // FIXME: Support error recovery for the template-name case. + bool CanRecover = !IsTemplateName; if (Corrected.isKeyword()) { // We corrected to a keyword. - diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II); + diagnoseTypo(Corrected, + PDiag(IsTemplateName ? diag::err_no_template_suggest + : diag::err_unknown_typename_suggest) + << II); II = Corrected.getCorrectionAsIdentifierInfo(); } else { // We found a similarly-named type or interface; suggest that. if (!SS || !SS->isSet()) { diagnoseTypo(Corrected, - PDiag(diag::err_unknown_typename_suggest) << II); + PDiag(IsTemplateName ? diag::err_no_template_suggest + : diag::err_unknown_typename_suggest) + << II, CanRecover); } else if (DeclContext *DC = computeDeclContext(*SS, false)) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && II->getName().equals(CorrectedStr); diagnoseTypo(Corrected, - PDiag(diag::err_unknown_nested_typename_suggest) - << II << DC << DroppedSpecifier << SS->getRange()); + PDiag(IsTemplateName + ? diag::err_no_member_template_suggest + : diag::err_unknown_nested_typename_suggest) + << II << DC << DroppedSpecifier << SS->getRange(), + CanRecover); } else { llvm_unreachable("could not have corrected a typo here"); } + if (!CanRecover) + return; + CXXScopeSpec tmpSS; if (Corrected.getCorrectionSpecifier()) tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(), @@ -675,7 +712,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, return; } - if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus && !IsTemplateName) { // See if II is a class template that the user forgot to pass arguments to. UnqualifiedId Name; Name.setIdentifier(II, IILoc); @@ -700,10 +737,13 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, // (struct, union, enum) from Parser::ParseImplicitInt here, instead? if (!SS || (!SS->isSet() && !SS->isInvalid())) - Diag(IILoc, diag::err_unknown_typename) << II; + Diag(IILoc, IsTemplateName ? diag::err_no_template + : diag::err_unknown_typename) + << II; else if (DeclContext *DC = computeDeclContext(*SS, false)) - Diag(IILoc, diag::err_typename_nested_not_found) - << II << DC << SS->getRange(); + Diag(IILoc, IsTemplateName ? diag::err_no_member_template + : diag::err_typename_nested_not_found) + << II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { unsigned DiagID = diag::err_typename_missing; if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S)) @@ -1488,6 +1528,11 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; + // A non-out-of-line declaration of a member specialization was implicitly + // instantiated; it's the out-of-line declaration that we're interested in. + if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && + FD->getMemberSpecializationInfo() && !FD->isOutOfLine()) + return false; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { if (MD->isVirtual() || IsDisallowedCopyOrAssign(MD)) @@ -1514,6 +1559,10 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; + if (VD->isStaticDataMember() && + VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && + VD->getMemberSpecializationInfo() && !VD->isOutOfLine()) + return false; if (VD->isInline() && !isMainFileLoc(*this, VD->getLocation())) return false; @@ -1972,7 +2021,7 @@ bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) { Diag(New->getLocation(), diag::err_redefinition_variably_modified_typedef) << Kind << NewType; if (Old->getLocation().isValid()) - Diag(Old->getLocation(), diag::note_previous_definition); + notePreviousDefinition(Old->getLocation(), New->getLocation()); New->setInvalidDecl(); return true; } @@ -1985,7 +2034,7 @@ bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) { Diag(New->getLocation(), diag::err_redefinition_different_typedef) << Kind << NewType << OldType; if (Old->getLocation().isValid()) - Diag(Old->getLocation(), diag::note_previous_definition); + notePreviousDefinition(Old->getLocation(), New->getLocation()); New->setInvalidDecl(); return true; } @@ -2052,7 +2101,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, NamedDecl *OldD = OldDecls.getRepresentativeDecl(); if (OldD->getLocation().isValid()) - Diag(OldD->getLocation(), diag::note_previous_definition); + notePreviousDefinition(OldD->getLocation(), New->getLocation()); return New->setInvalidDecl(); } @@ -2078,7 +2127,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, New->setTypeSourceInfo(OldTD->getTypeSourceInfo()); // Make the old tag definition visible. - makeMergedDefinitionVisible(Hidden, NewTag->getLocation()); + makeMergedDefinitionVisible(Hidden); // If this was an unscoped enumeration, yank all of its enumerators // out of the scope. @@ -2144,7 +2193,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); + notePreviousDefinition(Old->getLocation(), New->getLocation()); return New->setInvalidDecl(); } @@ -2165,7 +2214,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, Diag(New->getLocation(), diag::ext_redefinition_of_typedef) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); + notePreviousDefinition(Old->getLocation(), New->getLocation()); } /// DeclhasAttr - returns true if decl Declaration already has the target @@ -2452,7 +2501,10 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { ? diag::err_alias_after_tentative : diag::err_redefinition; S.Diag(VD->getLocation(), Diag) << VD->getDeclName(); - S.Diag(Def->getLocation(), diag::note_previous_definition); + if (Diag == diag::err_redefinition) + S.notePreviousDefinition(Def->getLocation(), VD->getLocation()); + else + S.Diag(Def->getLocation(), diag::note_previous_definition); VD->setInvalidDecl(); } ++I; @@ -2839,7 +2891,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, } else { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); - Diag(OldD->getLocation(), diag::note_previous_definition); + notePreviousDefinition(OldD->getLocation(), New->getLocation()); return true; } } @@ -2876,7 +2928,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, !Old->hasAttr<InternalLinkageAttr>()) { Diag(New->getLocation(), diag::err_internal_linkage_redeclaration) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); + notePreviousDefinition(Old->getLocation(), New->getLocation()); New->dropAttr<InternalLinkageAttr>(); } @@ -3604,9 +3656,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { } if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) - << New->getDeclName(); - Diag(Previous.getRepresentativeDecl()->getLocation(), - diag::note_previous_definition); + << New->getDeclName(); + notePreviousDefinition(Previous.getRepresentativeDecl()->getLocation(), + New->getLocation()); return New->setInvalidDecl(); } @@ -3635,7 +3687,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { Old->getStorageClass() == SC_None && !Old->hasAttr<WeakImportAttr>()) { Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); + notePreviousDefinition(Old->getLocation(), New->getLocation()); // Remove weak_import attribute on new declaration. New->dropAttr<WeakImportAttr>(); } @@ -3644,7 +3696,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { !Old->hasAttr<InternalLinkageAttr>()) { Diag(New->getLocation(), diag::err_internal_linkage_redeclaration) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); + notePreviousDefinition(Old->getLocation(), New->getLocation()); New->dropAttr<InternalLinkageAttr>(); } @@ -3801,6 +3853,67 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { New->setImplicitlyInline(); } +void Sema::notePreviousDefinition(SourceLocation Old, SourceLocation New) { + SourceManager &SrcMgr = getSourceManager(); + auto FNewDecLoc = SrcMgr.getDecomposedLoc(New); + auto FOldDecLoc = SrcMgr.getDecomposedLoc(Old); + auto *FNew = SrcMgr.getFileEntryForID(FNewDecLoc.first); + auto *FOld = SrcMgr.getFileEntryForID(FOldDecLoc.first); + auto &HSI = PP.getHeaderSearchInfo(); + StringRef HdrFilename = SrcMgr.getFilename(SrcMgr.getSpellingLoc(Old)); + + auto noteFromModuleOrInclude = [&](SourceLocation &Loc, + SourceLocation &IncLoc) -> bool { + Module *Mod = nullptr; + // Redefinition errors with modules are common with non modular mapped + // headers, example: a non-modular header H in module A that also gets + // included directly in a TU. Pointing twice to the same header/definition + // is confusing, try to get better diagnostics when modules is on. + if (getLangOpts().Modules) { + auto ModLoc = SrcMgr.getModuleImportLoc(Old); + if (!ModLoc.first.isInvalid()) + Mod = HSI.getModuleMap().inferModuleFromLocation( + FullSourceLoc(Loc, SrcMgr)); + } + + if (IncLoc.isValid()) { + if (Mod) { + Diag(IncLoc, diag::note_redefinition_modules_same_file) + << HdrFilename.str() << Mod->getFullModuleName(); + if (!Mod->DefinitionLoc.isInvalid()) + Diag(Mod->DefinitionLoc, diag::note_defined_here) + << Mod->getFullModuleName(); + } else { + Diag(IncLoc, diag::note_redefinition_include_same_file) + << HdrFilename.str(); + } + return true; + } + + return false; + }; + + // Is it the same file and same offset? Provide more information on why + // this leads to a redefinition error. + bool EmittedDiag = false; + if (FNew == FOld && FNewDecLoc.second == FOldDecLoc.second) { + SourceLocation OldIncLoc = SrcMgr.getIncludeLoc(FOldDecLoc.first); + SourceLocation NewIncLoc = SrcMgr.getIncludeLoc(FNewDecLoc.first); + EmittedDiag = noteFromModuleOrInclude(Old, OldIncLoc); + EmittedDiag |= noteFromModuleOrInclude(New, NewIncLoc); + + // If the header has no guards, emit a note suggesting one. + if (FOld && !HSI.isFileMultipleIncludeGuarded(FOld)) + Diag(Old, diag::note_use_ifdef_guards); + + if (EmittedDiag) + return; + } + + // Redefinition coming from different files or couldn't do better above. + Diag(Old, diag::note_previous_definition); +} + /// We've just determined that \p Old and \p New both appear to be definitions /// of the same variable. Either diagnose or fix the problem. bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) { @@ -3816,12 +3929,12 @@ bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) { // Make the canonical definition visible. if (auto *OldTD = Old->getDescribedVarTemplate()) - makeMergedDefinitionVisible(OldTD, New->getLocation()); - makeMergedDefinitionVisible(Old, New->getLocation()); + makeMergedDefinitionVisible(OldTD); + makeMergedDefinitionVisible(Old); return false; } else { Diag(New->getLocation(), diag::err_redefinition) << New; - Diag(Old->getLocation(), diag::note_previous_definition); + notePreviousDefinition(Old->getLocation(), New->getLocation()); New->setInvalidDecl(); return true; } @@ -6706,6 +6819,9 @@ NamedDecl *Sema::ActOnVariableDeclarator( return NewTemplate; } + if (IsMemberSpecialization && !NewVD->isInvalidDecl()) + CompleteMemberSpecialization(NewVD, Previous); + return NewVD; } @@ -8919,12 +9035,17 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } + MarkUnusedFileScopedDecl(NewFD); + if (getLangOpts().CPlusPlus) { if (FunctionTemplate) { if (NewFD->isInvalidDecl()) FunctionTemplate->setInvalidDecl(); return FunctionTemplate; } + + if (isMemberSpecialization && !NewFD->isInvalidDecl()) + CompleteMemberSpecialization(NewFD, Previous); } if (NewFD->hasAttr<OpenCLKernelAttr>()) { @@ -8964,8 +9085,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - MarkUnusedFileScopedDecl(NewFD); - // Here we have an function template explicit specialization at class scope. // The actually specialization will be postponed to template instatiation // time via the ClassScopeFunctionSpecializationDecl node. @@ -9182,7 +9301,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, if (OldTemplateDecl->getTemplatedDecl()->isDeleted()) { FunctionDecl *const OldTemplatedDecl = OldTemplateDecl->getTemplatedDecl(); + // FIXME: This assert will not hold in the presence of modules. assert(OldTemplatedDecl->getCanonicalDecl() == OldTemplatedDecl); + // FIXME: We need an update record for this AST mutation. OldTemplatedDecl->setDeletedAsWritten(false); } } @@ -10273,23 +10394,36 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { VDecl->setInit(Init); if (VDecl->isLocalVarDecl()) { + // Don't check the initializer if the declaration is malformed. + if (VDecl->isInvalidDecl()) { + // do nothing + + // OpenCL v1.2 s6.5.3: __constant locals must be constant-initialized. + // This is true even in OpenCL C++. + } else if (VDecl->getType().getAddressSpace() == LangAS::opencl_constant) { + CheckForConstantInitializer(Init, DclT); + + // Otherwise, C++ does not restrict the initializer. + } else if (getLangOpts().CPlusPlus) { + // do nothing + // C99 6.7.8p4: All the expressions in an initializer for an object that has // static storage duration shall be constant expressions or string literals. - // C++ does not have this restriction. - if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) { + } else if (VDecl->getStorageClass() == SC_Static) { + CheckForConstantInitializer(Init, DclT); + + // C89 is stricter than C99 for aggregate initializers. + // C89 6.5.7p3: All the expressions [...] in an initializer list + // for an object that has aggregate or union type shall be + // constant expressions. + } else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() && + isa<InitListExpr>(Init)) { const Expr *Culprit; - if (VDecl->getStorageClass() == SC_Static) - CheckForConstantInitializer(Init, DclT); - // C89 is stricter than C99 for non-static aggregate types. - // C89 6.5.7p3: All the expressions [...] in an initializer list - // for an object that has aggregate or union type shall be - // constant expressions. - else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() && - isa<InitListExpr>(Init) && - !Init->isConstantInitializer(Context, false, &Culprit)) + if (!Init->isConstantInitializer(Context, false, &Culprit)) { Diag(Culprit->getExprLoc(), diag::ext_aggregate_init_not_constant) << Culprit->getSourceRange(); + } } } else if (VDecl->isStaticDataMember() && !VDecl->isInline() && VDecl->getLexicalDeclContext()->isRecord()) { @@ -11023,8 +11157,7 @@ static bool hasDependentAlignment(VarDecl *VD) { /// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform /// any semantic actions necessary after any initializer has been attached. -void -Sema::FinalizeDeclaration(Decl *ThisDecl) { +void Sema::FinalizeDeclaration(Decl *ThisDecl) { // Note that we are no longer parsing the initializer for this declaration. ParsingInitForAutoVars.erase(ThisDecl); @@ -11189,9 +11322,8 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { if (DC->getRedeclContext()->isFileContext() && VD->isExternallyVisible()) AddPushedVisibilityAttribute(VD); - // FIXME: Warn on unused templates. - if (VD->isFileVarDecl() && !VD->getDescribedVarTemplate() && - !isa<VarTemplatePartialSpecializationDecl>(VD)) + // FIXME: Warn on unused var template partial specializations. + if (VD->isFileVarDecl() && !isa<VarTemplatePartialSpecializationDecl>(VD)) MarkUnusedFileScopedDecl(VD); // Now we have parsed the initializer and can update the table of magic @@ -11765,9 +11897,8 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, Definition->getNumTemplateParameterLists())) { SkipBody->ShouldSkip = true; if (auto *TD = Definition->getDescribedFunctionTemplate()) - makeMergedDefinitionVisible(TD, FD->getLocation()); - makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition), - FD->getLocation()); + makeMergedDefinitionVisible(TD); + makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition)); return; } @@ -13421,7 +13552,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // we already have. Make the existing definition visible and // use it in place of this one. SkipBody->ShouldSkip = true; - makeMergedDefinitionVisible(Hidden, KWLoc); + makeMergedDefinitionVisible(Hidden); return Def; } else if (!IsExplicitSpecializationAfterInstantiation) { // A redeclaration in function prototype scope in C isn't @@ -13430,7 +13561,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, Diag(NameLoc, diag::warn_redefinition_in_param_list) << Name; else Diag(NameLoc, diag::err_redefinition) << Name; - Diag(Def->getLocation(), diag::note_previous_definition); + notePreviousDefinition(Def->getLocation(), + NameLoc.isValid() ? NameLoc : KWLoc); // If this is a redefinition, recover by making this // struct be anonymous, which will make any later // references get the previous definition. @@ -13520,7 +13652,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // The tag name clashes with something else in the target scope, // issue an error and recover by making this tag be anonymous. Diag(NameLoc, diag::err_redefinition_different_kind) << Name; - Diag(PrevDecl->getLocation(), diag::note_previous_definition); + notePreviousDefinition(PrevDecl->getLocation(), NameLoc); Name = nullptr; Invalid = true; } @@ -13753,6 +13885,9 @@ CreateNewDecl: // record. AddPushedVisibilityAttribute(New); + if (isMemberSpecialization && !New->isInvalidDecl()) + CompleteMemberSpecialization(New, Previous); + OwnedDecl = true; // In C++, don't return an invalid declaration. We can't recover well from // the cases where we make the type anonymous. @@ -15221,7 +15356,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id; else Diag(IdLoc, diag::err_redefinition) << Id; - Diag(PrevDecl->getLocation(), diag::note_previous_definition); + notePreviousDefinition(PrevDecl->getLocation(), IdLoc); return nullptr; } } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 97d273f6ddb67..3de792e4e4064 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -7230,6 +7230,13 @@ public: SemaRef.Context.getTargetInfo().getPlatformMinVersion()); } + bool TraverseDecl(Decl *D) { + // Avoid visiting nested functions to prevent duplicate warnings. + if (!D || isa<FunctionDecl>(D)) + return true; + return Base::TraverseDecl(D); + } + bool TraverseStmt(Stmt *S) { if (!S) return true; @@ -7243,6 +7250,8 @@ public: bool TraverseIfStmt(IfStmt *If); + bool TraverseLambdaExpr(LambdaExpr *E) { return true; } + bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) { if (ObjCMethodDecl *D = Msg->getMethodDecl()) DiagnoseDeclAvailability( @@ -7346,7 +7355,9 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( llvm::raw_string_ostream FixItOS(FixItString); FixItOS << "if (" << (SemaRef.getLangOpts().ObjC1 ? "@available" : "__builtin_available") - << "(" << SemaRef.getASTContext().getTargetInfo().getPlatformName() + << "(" + << AvailabilityAttr::getPlatformNameSourceSpelling( + SemaRef.getASTContext().getTargetInfo().getPlatformName()) << " " << Introduced.getAsString() << ", *)) {\n" << Indentation << ExtraIndentation; FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str()); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 849e978e2d86e..14efc9672061a 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5277,6 +5277,9 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, // We aren't supposed to apply this logic if there's an '&' involved. if (!find.HasFormOfMemberPointer) { + if (Expr::hasAnyTypeDependentArguments(ArgExprs)) + return new (Context) CallExpr( + Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); OverloadExpr *ovl = find.Expression; if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(ovl)) return BuildOverloadedCallExpr( @@ -8028,6 +8031,33 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS, return QualType(); } +// Diagnose cases where a scalar was implicitly converted to a vector and +// diagnose the underlying types. Otherwise, diagnose the error +// as invalid vector logical operands for non-C++ cases. +QualType Sema::InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS, + ExprResult &RHS) { + QualType LHSType = LHS.get()->IgnoreImpCasts()->getType(); + QualType RHSType = RHS.get()->IgnoreImpCasts()->getType(); + + bool LHSNatVec = LHSType->isVectorType(); + bool RHSNatVec = RHSType->isVectorType(); + + if (!(LHSNatVec && RHSNatVec)) { + Expr *Vector = LHSNatVec ? LHS.get() : RHS.get(); + Expr *NonVector = !LHSNatVec ? LHS.get() : RHS.get(); + Diag(Loc, diag::err_typecheck_logical_vector_expr_gnu_cpp_restrict) + << 0 << Vector->getType() << NonVector->IgnoreImpCasts()->getType() + << Vector->getSourceRange(); + return QualType(); + } + + Diag(Loc, diag::err_typecheck_logical_vector_expr_gnu_cpp_restrict) + << 1 << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + + return QualType(); +} + /// Try to convert a value of non-vector type to a vector type by converting /// the type to the element type of the vector and then performing a splat. /// If the language is OpenCL, we only use conversions that promote scalar @@ -8075,6 +8105,162 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar, return false; } +/// Test if a (constant) integer Int can be casted to another integer type +/// IntTy without losing precision. +static bool canConvertIntToOtherIntTy(Sema &S, ExprResult *Int, + QualType OtherIntTy) { + QualType IntTy = Int->get()->getType().getUnqualifiedType(); + + // Reject cases where the value of the Int is unknown as that would + // possibly cause truncation, but accept cases where the scalar can be + // demoted without loss of precision. + llvm::APSInt Result; + bool CstInt = Int->get()->EvaluateAsInt(Result, S.Context); + int Order = S.Context.getIntegerTypeOrder(OtherIntTy, IntTy); + bool IntSigned = IntTy->hasSignedIntegerRepresentation(); + bool OtherIntSigned = OtherIntTy->hasSignedIntegerRepresentation(); + + if (CstInt) { + // If the scalar is constant and is of a higher order and has more active + // bits that the vector element type, reject it. + unsigned NumBits = IntSigned + ? (Result.isNegative() ? Result.getMinSignedBits() + : Result.getActiveBits()) + : Result.getActiveBits(); + if (Order < 0 && S.Context.getIntWidth(OtherIntTy) < NumBits) + return true; + + // If the signedness of the scalar type and the vector element type + // differs and the number of bits is greater than that of the vector + // element reject it. + return (IntSigned != OtherIntSigned && + NumBits > S.Context.getIntWidth(OtherIntTy)); + } + + // Reject cases where the value of the scalar is not constant and it's + // order is greater than that of the vector element type. + return (Order < 0); +} + +/// Test if a (constant) integer Int can be casted to floating point type +/// FloatTy without losing precision. +static bool canConvertIntTyToFloatTy(Sema &S, ExprResult *Int, + QualType FloatTy) { + QualType IntTy = Int->get()->getType().getUnqualifiedType(); + + // Determine if the integer constant can be expressed as a floating point + // number of the appropiate type. + llvm::APSInt Result; + bool CstInt = Int->get()->EvaluateAsInt(Result, S.Context); + uint64_t Bits = 0; + if (CstInt) { + // Reject constants that would be truncated if they were converted to + // the floating point type. Test by simple to/from conversion. + // FIXME: Ideally the conversion to an APFloat and from an APFloat + // could be avoided if there was a convertFromAPInt method + // which could signal back if implicit truncation occurred. + llvm::APFloat Float(S.Context.getFloatTypeSemantics(FloatTy)); + Float.convertFromAPInt(Result, IntTy->hasSignedIntegerRepresentation(), + llvm::APFloat::rmTowardZero); + llvm::APSInt ConvertBack(S.Context.getIntWidth(IntTy), + !IntTy->hasSignedIntegerRepresentation()); + bool Ignored = false; + Float.convertToInteger(ConvertBack, llvm::APFloat::rmNearestTiesToEven, + &Ignored); + if (Result != ConvertBack) + return true; + } else { + // Reject types that cannot be fully encoded into the mantissa of + // the float. + Bits = S.Context.getTypeSize(IntTy); + unsigned FloatPrec = llvm::APFloat::semanticsPrecision( + S.Context.getFloatTypeSemantics(FloatTy)); + if (Bits > FloatPrec) + return true; + } + + return false; +} + +/// Attempt to convert and splat Scalar into a vector whose types matches +/// Vector following GCC conversion rules. The rule is that implicit +/// conversion can occur when Scalar can be casted to match Vector's element +/// type without causing truncation of Scalar. +static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, + ExprResult *Vector) { + QualType ScalarTy = Scalar->get()->getType().getUnqualifiedType(); + QualType VectorTy = Vector->get()->getType().getUnqualifiedType(); + const VectorType *VT = VectorTy->getAs<VectorType>(); + + assert(!isa<ExtVectorType>(VT) && + "ExtVectorTypes should not be handled here!"); + + QualType VectorEltTy = VT->getElementType(); + + // Reject cases where the vector element type or the scalar element type are + // not integral or floating point types. + if (!VectorEltTy->isArithmeticType() || !ScalarTy->isArithmeticType()) + return true; + + // The conversion to apply to the scalar before splatting it, + // if necessary. + CastKind ScalarCast = CK_NoOp; + + // Accept cases where the vector elements are integers and the scalar is + // an integer. + // FIXME: Notionally if the scalar was a floating point value with a precise + // integral representation, we could cast it to an appropriate integer + // type and then perform the rest of the checks here. GCC will perform + // this conversion in some cases as determined by the input language. + // We should accept it on a language independent basis. + if (VectorEltTy->isIntegralType(S.Context) && + ScalarTy->isIntegralType(S.Context) && + S.Context.getIntegerTypeOrder(VectorEltTy, ScalarTy)) { + + if (canConvertIntToOtherIntTy(S, Scalar, VectorEltTy)) + return true; + + ScalarCast = CK_IntegralCast; + } else if (VectorEltTy->isRealFloatingType()) { + if (ScalarTy->isRealFloatingType()) { + + // Reject cases where the scalar type is not a constant and has a higher + // Order than the vector element type. + llvm::APFloat Result(0.0); + bool CstScalar = Scalar->get()->EvaluateAsFloat(Result, S.Context); + int Order = S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy); + if (!CstScalar && Order < 0) + return true; + + // If the scalar cannot be safely casted to the vector element type, + // reject it. + if (CstScalar) { + bool Truncated = false; + Result.convert(S.Context.getFloatTypeSemantics(VectorEltTy), + llvm::APFloat::rmNearestTiesToEven, &Truncated); + if (Truncated) + return true; + } + + ScalarCast = CK_FloatingCast; + } else if (ScalarTy->isIntegralType(S.Context)) { + if (canConvertIntTyToFloatTy(S, Scalar, VectorEltTy)) + return true; + + ScalarCast = CK_IntegralToFloating; + } else + return true; + } + + // Adjust scalar if desired. + if (Scalar) { + if (ScalarCast != CK_NoOp) + *Scalar = S.ImpCastExprToType(Scalar->get(), VectorEltTy, ScalarCast); + *Scalar = S.ImpCastExprToType(Scalar->get(), VectorTy, CK_VectorSplat); + } + return false; +} + QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool AllowBothBool, @@ -8143,19 +8329,29 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, } } - // If there's an ext-vector type and a scalar, try to convert the scalar to + // If there's a vector type and a scalar, try to convert the scalar to // the vector element type and splat. - // FIXME: this should also work for regular vector types as supported in GCC. - if (!RHSVecType && isa<ExtVectorType>(LHSVecType)) { - if (!tryVectorConvertAndSplat(*this, &RHS, RHSType, - LHSVecType->getElementType(), LHSType)) - return LHSType; + if (!RHSVecType) { + if (isa<ExtVectorType>(LHSVecType)) { + if (!tryVectorConvertAndSplat(*this, &RHS, RHSType, + LHSVecType->getElementType(), LHSType)) + return LHSType; + } else { + if (!tryGCCVectorConvertAndSplat(*this, &RHS, &LHS)) + return LHSType; + } } - if (!LHSVecType && isa<ExtVectorType>(RHSVecType)) { - if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS), - LHSType, RHSVecType->getElementType(), - RHSType)) - return RHSType; + if (!LHSVecType) { + if (isa<ExtVectorType>(RHSVecType)) { + if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS), + LHSType, RHSVecType->getElementType(), + RHSType)) + return RHSType; + } else { + if (LHS.get()->getValueKind() == VK_LValue || + !tryGCCVectorConvertAndSplat(*this, &LHS, &RHS)) + return RHSType; + } } // FIXME: The code below also handles conversion between vectors and @@ -8208,6 +8404,22 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, return QualType(); } + + // If there is a vector type that is not a ExtVector and a scalar, we reach + // this point if scalar could not be converted to the vector's element type + // without truncation. + if ((RHSVecType && !isa<ExtVectorType>(RHSVecType)) || + (LHSVecType && !isa<ExtVectorType>(LHSVecType))) { + QualType Scalar = LHSVecType ? RHSType : LHSType; + QualType Vector = LHSVecType ? LHSType : RHSType; + unsigned ScalarOrVector = LHSVecType && RHSVecType ? 1 : 0; + Diag(Loc, + diag::err_typecheck_vector_not_convertable_implict_truncation) + << ScalarOrVector << Scalar << Vector; + + return QualType(); + } + // Otherwise, use the generic diagnostic. Diag(Loc, diag::err_typecheck_vector_not_convertable) << LHSType << RHSType @@ -9827,6 +10039,12 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 && vType->hasFloatingRepresentation()) return InvalidOperands(Loc, LHS, RHS); + // FIXME: The check for C++ here is for GCC compatibility. GCC rejects the + // usage of the logical operators && and || with vectors in C. This + // check could be notionally dropped. + if (!getLangOpts().CPlusPlus && + !(isa<ExtVectorType>(vType->getAs<VectorType>()))) + return InvalidLogicalVectorOperands(Loc, LHS, RHS); return GetSignedVectorType(LHS.get()->getType()); } @@ -11770,6 +11988,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType = GetSignedVectorType(resultType); break; } else { + // FIXME: GCC's vector extension permits the usage of '!' with a vector + // type in C++. We should allow that here too. return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 9b88cddbc9698..8500b748a3ecd 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -4720,10 +4720,24 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // regard to cv-qualifiers. const RecordType *lhsRecord = LhsT->getAs<RecordType>(); - if (!lhsRecord) return false; - const RecordType *rhsRecord = RhsT->getAs<RecordType>(); - if (!rhsRecord) return false; + if (!rhsRecord || !lhsRecord) { + const ObjCObjectType *LHSObjTy = LhsT->getAs<ObjCObjectType>(); + const ObjCObjectType *RHSObjTy = RhsT->getAs<ObjCObjectType>(); + if (!LHSObjTy || !RHSObjTy) + return false; + + ObjCInterfaceDecl *BaseInterface = LHSObjTy->getInterface(); + ObjCInterfaceDecl *DerivedInterface = RHSObjTy->getInterface(); + if (!BaseInterface || !DerivedInterface) + return false; + + if (Self.RequireCompleteType( + KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) + return false; + + return BaseInterface->isSuperClassOf(DerivedInterface); + } assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT) == (lhsRecord == rhsRecord)); @@ -5342,6 +5356,15 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // C++11 [expr.cond]p1 // The first expression is contextually converted to bool. + // + // FIXME; GCC's vector extension permits the use of a?b:c where the type of + // a is that of a integer vector with the same number of elements and + // size as the vectors of b and c. If one of either b or c is a scalar + // it is implicitly converted to match the type of the vector. + // Otherwise the expression is ill-formed. If both b and c are scalars, + // then b and c are checked and converted to the type of a if possible. + // Unlike the OpenCL ?: operator, the expression is evaluated as + // (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]). if (!Cond.get()->isTypeDependent()) { ExprResult CondRes = CheckCXXBooleanCondition(Cond.get()); if (CondRes.isInvalid()) diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index a44e9243e3c52..28581bad1a7a4 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -4241,8 +4241,7 @@ void Sema::diagnoseARCUnbridgedCast(Expr *e) { castType = cast->getTypeAsWritten(); CCK = CCK_OtherCast; } else { - castType = cast->getType(); - CCK = CCK_ImplicitConversion; + llvm_unreachable("Unexpected ImplicitCastExpr"); } ARCConversionTypeClass castACTC = diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index d0f530010a0d1..32024cb335dc3 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -1209,7 +1209,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, } else { assert((ElemType->isRecordType() || ElemType->isVectorType() || - ElemType->isClkEventT()) && "Unexpected type"); + ElemType->isOpenCLSpecificType()) && "Unexpected type"); // C99 6.7.8p13: // @@ -8296,8 +8296,46 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity, AllowExplicit); InitializationSequence Seq(*this, Entity, Kind, InitE, TopLevelOfInitList); + // Prevent infinite recursion when performing parameter copy-initialization. + const bool ShouldTrackCopy = + Entity.isParameterKind() && Seq.isConstructorInitialization(); + if (ShouldTrackCopy) { + if (llvm::find(CurrentParameterCopyTypes, Entity.getType()) != + CurrentParameterCopyTypes.end()) { + Seq.SetOverloadFailure( + InitializationSequence::FK_ConstructorOverloadFailed, + OR_No_Viable_Function); + + // Try to give a meaningful diagnostic note for the problematic + // constructor. + const auto LastStep = Seq.step_end() - 1; + assert(LastStep->Kind == + InitializationSequence::SK_ConstructorInitialization); + const FunctionDecl *Function = LastStep->Function.Function; + auto Candidate = + llvm::find_if(Seq.getFailedCandidateSet(), + [Function](const OverloadCandidate &Candidate) -> bool { + return Candidate.Viable && + Candidate.Function == Function && + Candidate.Conversions.size() > 0; + }); + if (Candidate != Seq.getFailedCandidateSet().end() && + Function->getNumParams() > 0) { + Candidate->Viable = false; + Candidate->FailureKind = ovl_fail_bad_conversion; + Candidate->Conversions[0].setBad(BadConversionSequence::no_conversion, + InitE, + Function->getParamDecl(0)->getType()); + } + } + CurrentParameterCopyTypes.push_back(Entity.getType()); + } + ExprResult Result = Seq.Perform(*this, Entity, Kind, InitE); + if (ShouldTrackCopy) + CurrentParameterCopyTypes.pop_back(); + return Result; } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index ce76e14982dbb..c5b579a4b2e9b 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1382,8 +1382,8 @@ Module *Sema::getOwningModule(Decl *Entity) { return M; } -void Sema::makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc) { - if (auto *M = PP.getModuleContainingLocation(Loc)) +void Sema::makeMergedDefinitionVisible(NamedDecl *ND) { + if (auto *M = getCurrentModule()) Context.mergeDefinitionIntoModule(ND, M); else // We're not building a module; just make the definition visible. @@ -1393,7 +1393,7 @@ void Sema::makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc) { // visible too. They're not (necessarily) within a mergeable DeclContext. if (auto *TD = dyn_cast<TemplateDecl>(ND)) for (auto *Param : *TD->getTemplateParameters()) - makeMergedDefinitionVisible(Param, Loc); + makeMergedDefinitionVisible(Param); } /// \brief Find the module in which the given declaration was defined. @@ -3445,7 +3445,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, bool QualifiedNameLookup, bool InBaseClass, VisibleDeclConsumer &Consumer, - VisibleDeclsRecord &Visited) { + VisibleDeclsRecord &Visited, + bool IncludeDependentBases = false) { if (!Ctx) return; @@ -3501,7 +3502,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, ShadowContextRAII Shadow(Visited); for (auto I : Ctx->using_directives()) { LookupVisibleDecls(I->getNominatedNamespace(), Result, - QualifiedNameLookup, InBaseClass, Consumer, Visited); + QualifiedNameLookup, InBaseClass, Consumer, Visited, + IncludeDependentBases); } } @@ -3513,14 +3515,28 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, for (const auto &B : Record->bases()) { QualType BaseType = B.getType(); - // Don't look into dependent bases, because name lookup can't look - // there anyway. - if (BaseType->isDependentType()) - continue; - - const RecordType *Record = BaseType->getAs<RecordType>(); - if (!Record) - continue; + RecordDecl *RD; + if (BaseType->isDependentType()) { + if (!IncludeDependentBases) { + // Don't look into dependent bases, because name lookup can't look + // there anyway. + continue; + } + const auto *TST = BaseType->getAs<TemplateSpecializationType>(); + if (!TST) + continue; + TemplateName TN = TST->getTemplateName(); + const auto *TD = + dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl()); + if (!TD) + continue; + RD = TD->getTemplatedDecl(); + } else { + const auto *Record = BaseType->getAs<RecordType>(); + if (!Record) + continue; + RD = Record->getDecl(); + } // FIXME: It would be nice to be able to determine whether referencing // a particular member would be ambiguous. For example, given @@ -3543,8 +3559,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Find results in this base class (and its bases). ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup, - true, Consumer, Visited); + LookupVisibleDecls(RD, Result, QualifiedNameLookup, true, Consumer, + Visited, IncludeDependentBases); } } @@ -3713,7 +3729,8 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, - bool IncludeGlobalScope) { + bool IncludeGlobalScope, + bool IncludeDependentBases) { LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); Result.setAllowHidden(Consumer.includeHiddenDecls()); VisibleDeclsRecord Visited; @@ -3721,7 +3738,8 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, - /*InBaseClass=*/false, Consumer, Visited); + /*InBaseClass=*/false, Consumer, Visited, + IncludeDependentBases); } /// LookupOrCreateLabel - Do a name lookup of a label with the specified name. diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 782c377e32025..51794160278ca 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -11210,12 +11210,12 @@ Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E, /// \brief Given an overloaded function, tries to turn it into a non-overloaded /// function reference using resolveAddressOfOnlyViableOverloadCandidate. This /// will perform access checks, diagnose the use of the resultant decl, and, if -/// necessary, perform a function-to-pointer decay. +/// requested, potentially perform a function-to-pointer decay. /// /// Returns false if resolveAddressOfOnlyViableOverloadCandidate fails. /// Otherwise, returns true. This may emit diagnostics and return true. bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate( - ExprResult &SrcExpr) { + ExprResult &SrcExpr, bool DoFunctionPointerConverion) { Expr *E = SrcExpr.get(); assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload"); @@ -11230,7 +11230,7 @@ bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate( DiagnoseUseOfDecl(Found, E->getExprLoc()); CheckAddressOfMemberAccess(E, DAP); Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found); - if (Fixed->getType()->isFunctionType()) + if (DoFunctionPointerConverion && Fixed->getType()->isFunctionType()) SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false); else SrcExpr = Fixed; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 5d7eada287173..33a8f9c4afa35 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -2268,9 +2268,57 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, BoundExpr = IntegerLiteral::Create( Context, CAT->getSize(), Context.getPointerDiffType(), RangeLoc); else if (const VariableArrayType *VAT = - dyn_cast<VariableArrayType>(UnqAT)) - BoundExpr = VAT->getSizeExpr(); - else { + dyn_cast<VariableArrayType>(UnqAT)) { + // For a variably modified type we can't just use the expression within + // the array bounds, since we don't want that to be re-evaluated here. + // Rather, we need to determine what it was when the array was first + // created - so we resort to using sizeof(vla)/sizeof(element). + // For e.g. + // void f(int b) { + // int vla[b]; + // b = -1; <-- This should not affect the num of iterations below + // for (int &c : vla) { .. } + // } + + // FIXME: This results in codegen generating IR that recalculates the + // run-time number of elements (as opposed to just using the IR Value + // that corresponds to the run-time value of each bound that was + // generated when the array was created.) If this proves too embarassing + // even for unoptimized IR, consider passing a magic-value/cookie to + // codegen that then knows to simply use that initial llvm::Value (that + // corresponds to the bound at time of array creation) within + // getelementptr. But be prepared to pay the price of increasing a + // customized form of coupling between the two components - which could + // be hard to maintain as the codebase evolves. + + ExprResult SizeOfVLAExprR = ActOnUnaryExprOrTypeTraitExpr( + EndVar->getLocation(), UETT_SizeOf, + /*isType=*/true, + CreateParsedType(VAT->desugar(), Context.getTrivialTypeSourceInfo( + VAT->desugar(), RangeLoc)) + .getAsOpaquePtr(), + EndVar->getSourceRange()); + if (SizeOfVLAExprR.isInvalid()) + return StmtError(); + + ExprResult SizeOfEachElementExprR = ActOnUnaryExprOrTypeTraitExpr( + EndVar->getLocation(), UETT_SizeOf, + /*isType=*/true, + CreateParsedType(VAT->desugar(), + Context.getTrivialTypeSourceInfo( + VAT->getElementType(), RangeLoc)) + .getAsOpaquePtr(), + EndVar->getSourceRange()); + if (SizeOfEachElementExprR.isInvalid()) + return StmtError(); + + BoundExpr = + ActOnBinOp(S, EndVar->getLocation(), tok::slash, + SizeOfVLAExprR.get(), SizeOfEachElementExprR.get()); + if (BoundExpr.isInvalid()) + return StmtError(); + + } else { // Can't be a DependentSizedArrayType or an IncompleteArrayType since // UnqAT is not incomplete and Range is not type-dependent. llvm_unreachable("Unexpected array type in for-range"); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 61b4df40964c6..a479d1027533e 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -455,6 +455,85 @@ void Sema::LookupTemplateName(LookupResult &Found, } } +void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, + SourceLocation Less, + SourceLocation Greater) { + if (TemplateName.isInvalid()) + return; + + DeclarationNameInfo NameInfo; + CXXScopeSpec SS; + LookupNameKind LookupKind; + + DeclContext *LookupCtx = nullptr; + NamedDecl *Found = nullptr; + + // Figure out what name we looked up. + if (auto *ME = dyn_cast<MemberExpr>(TemplateName.get())) { + NameInfo = ME->getMemberNameInfo(); + SS.Adopt(ME->getQualifierLoc()); + LookupKind = LookupMemberName; + LookupCtx = ME->getBase()->getType()->getAsCXXRecordDecl(); + Found = ME->getMemberDecl(); + } else { + auto *DRE = cast<DeclRefExpr>(TemplateName.get()); + NameInfo = DRE->getNameInfo(); + SS.Adopt(DRE->getQualifierLoc()); + LookupKind = LookupOrdinaryName; + Found = DRE->getFoundDecl(); + } + + // Try to correct the name by looking for templates and C++ named casts. + struct TemplateCandidateFilter : CorrectionCandidateCallback { + TemplateCandidateFilter() { + WantTypeSpecifiers = false; + WantExpressionKeywords = false; + WantRemainingKeywords = false; + WantCXXNamedCasts = true; + }; + bool ValidateCandidate(const TypoCorrection &Candidate) override { + if (auto *ND = Candidate.getCorrectionDecl()) + return isAcceptableTemplateName(ND->getASTContext(), ND, true); + return Candidate.isKeyword(); + } + }; + + DeclarationName Name = NameInfo.getName(); + if (TypoCorrection Corrected = + CorrectTypo(NameInfo, LookupKind, S, &SS, + llvm::make_unique<TemplateCandidateFilter>(), + CTK_ErrorRecovery, LookupCtx)) { + auto *ND = Corrected.getFoundDecl(); + if (ND) + ND = isAcceptableTemplateName(Context, ND, + /*AllowFunctionTemplates*/ true); + if (ND || Corrected.isKeyword()) { + if (LookupCtx) { + std::string CorrectedStr(Corrected.getAsString(getLangOpts())); + bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && + Name.getAsString() == CorrectedStr; + diagnoseTypo(Corrected, + PDiag(diag::err_non_template_in_member_template_id_suggest) + << Name << LookupCtx << DroppedSpecifier + << SS.getRange(), false); + } else { + diagnoseTypo(Corrected, + PDiag(diag::err_non_template_in_template_id_suggest) + << Name, false); + } + if (Found) + Diag(Found->getLocation(), + diag::note_non_template_in_template_id_found); + return; + } + } + + Diag(NameInfo.getLoc(), diag::err_non_template_in_template_id) + << Name << SourceRange(Less, Greater); + if (Found) + Diag(Found->getLocation(), diag::note_non_template_in_template_id_found); +} + /// ActOnDependentIdExpression - Handle a dependent id-expression that /// was just parsed. This is only possible with an explicit scope /// specifier naming a dependent type. @@ -1251,8 +1330,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate(); assert(Tmpl && "original definition of a class template is not a " "class template?"); - makeMergedDefinitionVisible(Hidden, KWLoc); - makeMergedDefinitionVisible(Tmpl, KWLoc); + makeMergedDefinitionVisible(Hidden); + makeMergedDefinitionVisible(Tmpl); return Def; } @@ -7352,7 +7431,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, NamedDecl *Hidden = nullptr; if (Def && SkipBody && !hasVisibleDefinition(Def, &Hidden)) { SkipBody->ShouldSkip = true; - makeMergedDefinitionVisible(Hidden, KWLoc); + makeMergedDefinitionVisible(Hidden); // From here on out, treat this as just a redeclaration. TUK = TUK_Declaration; } else if (Def) { @@ -7825,6 +7904,9 @@ bool Sema::CheckFunctionTemplateSpecialization( // C++11 [dcl.constexpr]p1: An explicit specialization of a constexpr // function can differ from the template declaration with respect to // the constexpr specifier. + // FIXME: We need an update record for this AST mutation. + // FIXME: What if there are multiple such prior declarations (for instance, + // from different modules)? Specialization->setConstexpr(FD->isConstexpr()); } @@ -7872,9 +7954,11 @@ bool Sema::CheckFunctionTemplateSpecialization( // flag to not-deleted, so that we can inherit that information from 'FD'. if (Specialization->isDeleted() && !SpecInfo->isExplicitSpecialization() && !Specialization->getCanonicalDecl()->isReferenced()) { + // FIXME: This assert will not hold in the presence of modules. assert( Specialization->getCanonicalDecl() == Specialization && "This must be the only existing declaration of this specialization"); + // FIXME: We need an update record for this AST mutation. Specialization->setDeletedAsWritten(false); } SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); @@ -7987,8 +8071,11 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { return false; } - // If this is a friend, just bail out here before we start turning - // things into explicit specializations. + // A member specialization in a friend declaration isn't really declaring + // an explicit specialization, just identifying a specific (possibly implicit) + // specialization. Don't change the template specialization kind. + // + // FIXME: Is this really valid? Other compilers reject. if (Member->getFriendObjectKind() != Decl::FOK_None) { // Preserve instantiation information. if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) { @@ -8038,66 +8125,36 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { false)) return true; - // Note that this is an explicit instantiation of a member. - // the original declaration to note that it is an explicit specialization - // (if it was previously an implicit instantiation). This latter step - // makes bookkeeping easier. - if (isa<FunctionDecl>(Member)) { + // Note that this member specialization is an "instantiation of" the + // corresponding member of the original template. + if (auto *MemberFunction = dyn_cast<FunctionDecl>(Member)) { FunctionDecl *InstantiationFunction = cast<FunctionDecl>(Instantiation); if (InstantiationFunction->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) { - InstantiationFunction->setTemplateSpecializationKind( - TSK_ExplicitSpecialization); - InstantiationFunction->setLocation(Member->getLocation()); // Explicit specializations of member functions of class templates do not // inherit '=delete' from the member function they are specializing. if (InstantiationFunction->isDeleted()) { + // FIXME: This assert will not hold in the presence of modules. assert(InstantiationFunction->getCanonicalDecl() == InstantiationFunction); + // FIXME: We need an update record for this AST mutation. InstantiationFunction->setDeletedAsWritten(false); } } - cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction( - cast<CXXMethodDecl>(InstantiatedFrom), - TSK_ExplicitSpecialization); - MarkUnusedFileScopedDecl(InstantiationFunction); - } else if (isa<VarDecl>(Member)) { - VarDecl *InstantiationVar = cast<VarDecl>(Instantiation); - if (InstantiationVar->getTemplateSpecializationKind() == - TSK_ImplicitInstantiation) { - InstantiationVar->setTemplateSpecializationKind( - TSK_ExplicitSpecialization); - InstantiationVar->setLocation(Member->getLocation()); - } - - cast<VarDecl>(Member)->setInstantiationOfStaticDataMember( + MemberFunction->setInstantiationOfMemberFunction( + cast<CXXMethodDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); + } else if (auto *MemberVar = dyn_cast<VarDecl>(Member)) { + MemberVar->setInstantiationOfStaticDataMember( cast<VarDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); - MarkUnusedFileScopedDecl(InstantiationVar); - } else if (isa<CXXRecordDecl>(Member)) { - CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation); - if (InstantiationClass->getTemplateSpecializationKind() == - TSK_ImplicitInstantiation) { - InstantiationClass->setTemplateSpecializationKind( - TSK_ExplicitSpecialization); - InstantiationClass->setLocation(Member->getLocation()); - } - - cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass( - cast<CXXRecordDecl>(InstantiatedFrom), - TSK_ExplicitSpecialization); - } else { - assert(isa<EnumDecl>(Member) && "Only member enums remain"); - EnumDecl *InstantiationEnum = cast<EnumDecl>(Instantiation); - if (InstantiationEnum->getTemplateSpecializationKind() == - TSK_ImplicitInstantiation) { - InstantiationEnum->setTemplateSpecializationKind( - TSK_ExplicitSpecialization); - InstantiationEnum->setLocation(Member->getLocation()); - } - - cast<EnumDecl>(Member)->setInstantiationOfMemberEnum( + } else if (auto *MemberClass = dyn_cast<CXXRecordDecl>(Member)) { + MemberClass->setInstantiationOfMemberClass( + cast<CXXRecordDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); + } else if (auto *MemberEnum = dyn_cast<EnumDecl>(Member)) { + MemberEnum->setInstantiationOfMemberEnum( cast<EnumDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); + } else { + llvm_unreachable("unknown member specialization kind"); } // Save the caller the trouble of having to figure out which declaration @@ -8107,6 +8164,43 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { return false; } +/// Complete the explicit specialization of a member of a class template by +/// updating the instantiated member to be marked as an explicit specialization. +/// +/// \param OrigD The member declaration instantiated from the template. +/// \param Loc The location of the explicit specialization of the member. +template<typename DeclT> +static void completeMemberSpecializationImpl(Sema &S, DeclT *OrigD, + SourceLocation Loc) { + if (OrigD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) + return; + + // FIXME: Inform AST mutation listeners of this AST mutation. + // FIXME: If there are multiple in-class declarations of the member (from + // multiple modules, or a declaration and later definition of a member type), + // should we update all of them? + OrigD->setTemplateSpecializationKind(TSK_ExplicitSpecialization); + OrigD->setLocation(Loc); +} + +void Sema::CompleteMemberSpecialization(NamedDecl *Member, + LookupResult &Previous) { + NamedDecl *Instantiation = cast<NamedDecl>(Member->getCanonicalDecl()); + if (Instantiation == Member) + return; + + if (auto *Function = dyn_cast<CXXMethodDecl>(Instantiation)) + completeMemberSpecializationImpl(*this, Function, Member->getLocation()); + else if (auto *Var = dyn_cast<VarDecl>(Instantiation)) + completeMemberSpecializationImpl(*this, Var, Member->getLocation()); + else if (auto *Record = dyn_cast<CXXRecordDecl>(Instantiation)) + completeMemberSpecializationImpl(*this, Record, Member->getLocation()); + else if (auto *Enum = dyn_cast<EnumDecl>(Instantiation)) + completeMemberSpecializationImpl(*this, Enum, Member->getLocation()); + else + llvm_unreachable("unknown member specialization kind"); +} + /// \brief Check the scope of an explicit instantiation. /// /// \returns true if a serious error occurs, false otherwise. diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9a71a17561c7c..03df6fde6c802 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1849,6 +1849,19 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } } } + + // Check the template parameter list against the previous declaration. The + // goal here is to pick up default arguments added since the friend was + // declared; we know the template parameter lists match, since otherwise + // we would not have picked this template as the previous declaration. + if (TemplateParams && FunctionTemplate->getPreviousDecl()) { + SemaRef.CheckTemplateParameterList( + TemplateParams, + FunctionTemplate->getPreviousDecl()->getTemplateParameters(), + Function->isThisDeclarationADefinition() + ? Sema::TPC_FriendFunctionTemplateDefinition + : Sema::TPC_FriendFunctionTemplate); + } } if (Function->isLocalExternDecl() && !Function->getPreviousDecl()) @@ -3660,6 +3673,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, New->setType(SemaRef.Context.getFunctionType( NewProto->getReturnType(), NewProto->getParamTypes(), EPI)); } else { + Sema::ContextRAII SwitchContext(SemaRef, New); SemaRef.SubstExceptionSpec(New, Proto, TemplateArgs); } } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index bcc66bbd1c0a2..3992179fabae3 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -2285,8 +2285,9 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { // Methods cannot return interface types. All ObjC objects are // passed by reference. if (T->isObjCObjectType()) { - Diag(Loc, diag::err_object_cannot_be_passed_returned_by_value) << 0 << T; - return 0; + Diag(Loc, diag::err_object_cannot_be_passed_returned_by_value) + << 0 << T << FixItHint::CreateInsertion(Loc, "*"); + return true; } return false; |