summaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp477
1 files changed, 303 insertions, 174 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4b9b735f1cfb..029ccf944c51 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1493,7 +1493,7 @@ void Sema::ActOnExitFunctionContext() {
///
/// This routine determines whether overloading is possible, not
/// whether a new declaration actually overloads a previous one.
-/// It will return true in C++ (where overloads are alway permitted)
+/// It will return true in C++ (where overloads are always permitted)
/// or, as a C extension, when either the new declaration or a
/// previous one is declared with the 'overloadable' attribute.
static bool AllowOverloadingOfFunction(const LookupResult &Previous,
@@ -1663,8 +1663,7 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
// Partitions are part of the module, but a partition could import another
// module, so verify that the PMIs agree.
if ((NewM->isModulePartition() || OldM->isModulePartition()) &&
- NewM->getPrimaryModuleInterfaceName() ==
- OldM->getPrimaryModuleInterfaceName())
+ getASTContext().isInSameModule(NewM, OldM))
return false;
}
@@ -3912,6 +3911,49 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
return true;
}
+ const auto OldFX = Old->getFunctionEffects();
+ const auto NewFX = New->getFunctionEffects();
+ QualType OldQTypeForComparison = OldQType;
+ if (OldFX != NewFX) {
+ const auto Diffs = FunctionEffectDifferences(OldFX, NewFX);
+ for (const auto &Diff : Diffs) {
+ if (Diff.shouldDiagnoseRedeclaration(*Old, OldFX, *New, NewFX)) {
+ Diag(New->getLocation(),
+ diag::warn_mismatched_func_effect_redeclaration)
+ << Diff.effectName();
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ }
+ }
+ // Following a warning, we could skip merging effects from the previous
+ // declaration, but that would trigger an additional "conflicting types"
+ // error.
+ if (const auto *NewFPT = NewQType->getAs<FunctionProtoType>()) {
+ FunctionEffectSet::Conflicts MergeErrs;
+ FunctionEffectSet MergedFX =
+ FunctionEffectSet::getUnion(OldFX, NewFX, MergeErrs);
+ if (!MergeErrs.empty())
+ diagnoseFunctionEffectMergeConflicts(MergeErrs, New->getLocation(),
+ Old->getLocation());
+
+ FunctionProtoType::ExtProtoInfo EPI = NewFPT->getExtProtoInfo();
+ EPI.FunctionEffects = FunctionEffectsRef(MergedFX);
+ QualType ModQT = Context.getFunctionType(NewFPT->getReturnType(),
+ NewFPT->getParamTypes(), EPI);
+
+ New->setType(ModQT);
+ NewQType = New->getType();
+
+ // Revise OldQTForComparison to include the merged effects,
+ // so as not to fail due to differences later.
+ if (const auto *OldFPT = OldQType->getAs<FunctionProtoType>()) {
+ EPI = OldFPT->getExtProtoInfo();
+ EPI.FunctionEffects = FunctionEffectsRef(MergedFX);
+ OldQTypeForComparison = Context.getFunctionType(
+ OldFPT->getReturnType(), OldFPT->getParamTypes(), EPI);
+ }
+ }
+ }
+
if (getLangOpts().CPlusPlus) {
OldQType = Context.getCanonicalType(Old->getType());
NewQType = Context.getCanonicalType(New->getType());
@@ -4076,9 +4118,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
// We also want to respect all the extended bits except noreturn.
// noreturn should now match unless the old type info didn't have it.
- QualType OldQTypeForComparison = OldQType;
if (!OldTypeInfo.getNoReturn() && NewTypeInfo.getNoReturn()) {
- auto *OldType = OldQType->castAs<FunctionProtoType>();
+ auto *OldType = OldQTypeForComparison->castAs<FunctionProtoType>();
const FunctionType *OldTypeForComparison
= Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true));
OldQTypeForComparison = QualType(OldTypeForComparison, 0);
@@ -4147,7 +4188,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
// If we are merging two functions where only one of them has a prototype,
// we may have enough information to decide to issue a diagnostic that the
- // function without a protoype will change behavior in C23. This handles
+ // function without a prototype will change behavior in C23. This handles
// cases like:
// void i(); void i(int j);
// void i(int j); void i();
@@ -7609,80 +7650,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
NTCUC_AutoVar, NTCUK_Destruct);
} else {
bool Invalid = false;
-
- if (DC->isRecord() && !CurContext->isRecord()) {
- // This is an out-of-line definition of a static data member.
- switch (SC) {
- case SC_None:
- break;
- case SC_Static:
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
- diag::err_static_out_of_line)
- << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
- break;
- case SC_Auto:
- case SC_Register:
- case SC_Extern:
- // [dcl.stc] p2: The auto or register specifiers shall be applied only
- // to names of variables declared in a block or to function parameters.
- // [dcl.stc] p6: The extern specifier cannot be used in the declaration
- // of class members
-
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
- diag::err_storage_class_for_static_member)
- << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
- break;
- case SC_PrivateExtern:
- llvm_unreachable("C storage class in c++!");
- }
- }
-
- if (SC == SC_Static && CurContext->isRecord()) {
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
- // Walk up the enclosing DeclContexts to check for any that are
- // incompatible with static data members.
- const DeclContext *FunctionOrMethod = nullptr;
- const CXXRecordDecl *AnonStruct = nullptr;
- for (DeclContext *Ctxt = DC; Ctxt; Ctxt = Ctxt->getParent()) {
- if (Ctxt->isFunctionOrMethod()) {
- FunctionOrMethod = Ctxt;
- break;
- }
- const CXXRecordDecl *ParentDecl = dyn_cast<CXXRecordDecl>(Ctxt);
- if (ParentDecl && !ParentDecl->getDeclName()) {
- AnonStruct = ParentDecl;
- break;
- }
- }
- if (FunctionOrMethod) {
- // C++ [class.static.data]p5: A local class shall not have static data
- // members.
- Diag(D.getIdentifierLoc(),
- diag::err_static_data_member_not_allowed_in_local_class)
- << Name << RD->getDeclName()
- << llvm::to_underlying(RD->getTagKind());
- } else if (AnonStruct) {
- // C++ [class.static.data]p4: Unnamed classes and classes contained
- // directly or indirectly within unnamed classes shall not contain
- // static data members.
- Diag(D.getIdentifierLoc(),
- diag::err_static_data_member_not_allowed_in_anon_struct)
- << Name << llvm::to_underlying(AnonStruct->getTagKind());
- Invalid = true;
- } else if (RD->isUnion()) {
- // C++98 [class.union]p1: If a union contains a static data member,
- // the program is ill-formed. C++11 drops this restriction.
- Diag(D.getIdentifierLoc(),
- getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_static_data_member_in_union
- : diag::ext_static_data_member_in_union) << Name;
- }
- }
- }
-
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
- bool InvalidScope = false;
TemplateParams = MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
D.getCXXScopeSpec(),
@@ -7690,8 +7659,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
? D.getName().TemplateId
: nullptr,
TemplateParamLists,
- /*never a friend*/ false, IsMemberSpecialization, InvalidScope);
- Invalid |= InvalidScope;
+ /*never a friend*/ false, IsMemberSpecialization, Invalid);
if (TemplateParams) {
if (!TemplateParams->size() &&
@@ -7734,6 +7702,102 @@ NamedDecl *Sema::ActOnVariableDeclarator(
"should have a 'template<>' for this decl");
}
+ bool IsExplicitSpecialization =
+ IsVariableTemplateSpecialization && !IsPartialSpecialization;
+
+ // C++ [temp.expl.spec]p2:
+ // The declaration in an explicit-specialization shall not be an
+ // export-declaration. An explicit specialization shall not use a
+ // storage-class-specifier other than thread_local.
+ //
+ // We use the storage-class-specifier from DeclSpec because we may have
+ // added implicit 'extern' for declarations with __declspec(dllimport)!
+ if (SCSpec != DeclSpec::SCS_unspecified &&
+ (IsExplicitSpecialization || IsMemberSpecialization)) {
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::ext_explicit_specialization_storage_class)
+ << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+ }
+
+ if (CurContext->isRecord()) {
+ if (SC == SC_Static) {
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
+ // Walk up the enclosing DeclContexts to check for any that are
+ // incompatible with static data members.
+ const DeclContext *FunctionOrMethod = nullptr;
+ const CXXRecordDecl *AnonStruct = nullptr;
+ for (DeclContext *Ctxt = DC; Ctxt; Ctxt = Ctxt->getParent()) {
+ if (Ctxt->isFunctionOrMethod()) {
+ FunctionOrMethod = Ctxt;
+ break;
+ }
+ const CXXRecordDecl *ParentDecl = dyn_cast<CXXRecordDecl>(Ctxt);
+ if (ParentDecl && !ParentDecl->getDeclName()) {
+ AnonStruct = ParentDecl;
+ break;
+ }
+ }
+ if (FunctionOrMethod) {
+ // C++ [class.static.data]p5: A local class shall not have static
+ // data members.
+ Diag(D.getIdentifierLoc(),
+ diag::err_static_data_member_not_allowed_in_local_class)
+ << Name << RD->getDeclName()
+ << llvm::to_underlying(RD->getTagKind());
+ } else if (AnonStruct) {
+ // C++ [class.static.data]p4: Unnamed classes and classes contained
+ // directly or indirectly within unnamed classes shall not contain
+ // static data members.
+ Diag(D.getIdentifierLoc(),
+ diag::err_static_data_member_not_allowed_in_anon_struct)
+ << Name << llvm::to_underlying(AnonStruct->getTagKind());
+ Invalid = true;
+ } else if (RD->isUnion()) {
+ // C++98 [class.union]p1: If a union contains a static data member,
+ // the program is ill-formed. C++11 drops this restriction.
+ Diag(D.getIdentifierLoc(),
+ getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_static_data_member_in_union
+ : diag::ext_static_data_member_in_union)
+ << Name;
+ }
+ }
+ } else if (IsVariableTemplate || IsPartialSpecialization) {
+ // There is no such thing as a member field template.
+ Diag(D.getIdentifierLoc(), diag::err_template_member)
+ << II << TemplateParams->getSourceRange();
+ // Recover by pretending this is a static data member template.
+ SC = SC_Static;
+ }
+ } else if (DC->isRecord()) {
+ // This is an out-of-line definition of a static data member.
+ switch (SC) {
+ case SC_None:
+ break;
+ case SC_Static:
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::err_static_out_of_line)
+ << FixItHint::CreateRemoval(
+ D.getDeclSpec().getStorageClassSpecLoc());
+ break;
+ case SC_Auto:
+ case SC_Register:
+ case SC_Extern:
+ // [dcl.stc] p2: The auto or register specifiers shall be applied only
+ // to names of variables declared in a block or to function parameters.
+ // [dcl.stc] p6: The extern specifier cannot be used in the declaration
+ // of class members
+
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::err_storage_class_for_static_member)
+ << FixItHint::CreateRemoval(
+ D.getDeclSpec().getStorageClassSpecLoc());
+ break;
+ case SC_PrivateExtern:
+ llvm_unreachable("C storage class in c++!");
+ }
+ }
+
if (IsVariableTemplateSpecialization) {
SourceLocation TemplateKWLoc =
TemplateParamLists.size() > 0
@@ -7779,8 +7843,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// the variable (matching the scope specifier), store them.
// An explicit variable template specialization does not own any template
// parameter lists.
- bool IsExplicitSpecialization =
- IsVariableTemplateSpecialization && !IsPartialSpecialization;
unsigned VDTemplateParamLists =
(TemplateParams && !IsExplicitSpecialization) ? 1 : 0;
if (TemplateParamLists.size() > VDTemplateParamLists)
@@ -10210,25 +10272,45 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setImplicitlyInline(ImplicitInlineCXX20);
}
- if (SC == SC_Static && isa<CXXMethodDecl>(NewFD) &&
- !CurContext->isRecord()) {
- // C++ [class.static]p1:
- // A data or function member of a class may be declared static
- // in a class definition, in which case it is a static member of
- // the class.
+ if (!isFriend && SC != SC_None) {
+ // C++ [temp.expl.spec]p2:
+ // The declaration in an explicit-specialization shall not be an
+ // export-declaration. An explicit specialization shall not use a
+ // storage-class-specifier other than thread_local.
+ //
+ // We diagnose friend declarations with storage-class-specifiers
+ // elsewhere.
+ if (isFunctionTemplateSpecialization || isMemberSpecialization) {
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::ext_explicit_specialization_storage_class)
+ << FixItHint::CreateRemoval(
+ D.getDeclSpec().getStorageClassSpecLoc());
+ }
- // Complain about the 'static' specifier if it's on an out-of-line
- // member function definition.
+ if (SC == SC_Static && !CurContext->isRecord() && DC->isRecord()) {
+ assert(isa<CXXMethodDecl>(NewFD) &&
+ "Out-of-line member function should be a CXXMethodDecl");
+ // C++ [class.static]p1:
+ // A data or function member of a class may be declared static
+ // in a class definition, in which case it is a static member of
+ // the class.
- // MSVC permits the use of a 'static' storage specifier on an out-of-line
- // member function template declaration and class member template
- // declaration (MSVC versions before 2015), warn about this.
- Diag(D.getDeclSpec().getStorageClassSpecLoc(),
- ((!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) &&
- cast<CXXRecordDecl>(DC)->getDescribedClassTemplate()) ||
- (getLangOpts().MSVCCompat && NewFD->getDescribedFunctionTemplate()))
- ? diag::ext_static_out_of_line : diag::err_static_out_of_line)
- << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+ // Complain about the 'static' specifier if it's on an out-of-line
+ // member function definition.
+
+ // MSVC permits the use of a 'static' storage specifier on an
+ // out-of-line member function template declaration and class member
+ // template declaration (MSVC versions before 2015), warn about this.
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ ((!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) &&
+ cast<CXXRecordDecl>(DC)->getDescribedClassTemplate()) ||
+ (getLangOpts().MSVCCompat &&
+ NewFD->getDescribedFunctionTemplate()))
+ ? diag::ext_static_out_of_line
+ : diag::err_static_out_of_line)
+ << FixItHint::CreateRemoval(
+ D.getDeclSpec().getStorageClassSpecLoc());
+ }
}
// C++11 [except.spec]p15:
@@ -10553,7 +10635,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (getLangOpts().CUDA && !isFunctionTemplateSpecialization)
CUDA().maybeAddHostDeviceAttrs(NewFD, Previous);
- // Handle explict specializations of function templates
+ // Handle explicit specializations of function templates
// and friend function declarations with an explicit
// template argument list.
if (isFunctionTemplateSpecialization) {
@@ -10596,27 +10678,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Previous))
NewFD->setInvalidDecl();
}
-
- // C++ [dcl.stc]p1:
- // A storage-class-specifier shall not be specified in an explicit
- // specialization (14.7.3)
- // FIXME: We should be checking this for dependent specializations.
- FunctionTemplateSpecializationInfo *Info =
- NewFD->getTemplateSpecializationInfo();
- if (Info && SC != SC_None) {
- if (SC != Info->getTemplate()->getTemplatedDecl()->getStorageClass())
- Diag(NewFD->getLocation(),
- diag::err_explicit_specialization_inconsistent_storage_class)
- << SC
- << FixItHint::CreateRemoval(
- D.getDeclSpec().getStorageClassSpecLoc());
-
- else
- Diag(NewFD->getLocation(),
- diag::ext_explicit_specialization_storage_class)
- << FixItHint::CreateRemoval(
- D.getDeclSpec().getStorageClassSpecLoc());
- }
} else if (isMemberSpecialization && isa<CXXMethodDecl>(NewFD)) {
if (CheckMemberSpecialization(NewFD, Previous))
NewFD->setInvalidDecl();
@@ -12601,7 +12662,7 @@ void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) {
if (FD->getName() != "DllMain")
FD->setHasImplicitReturnZero(true);
- // Explicity specified calling conventions are applied to MSVC entry points
+ // Explicitly specified calling conventions are applied to MSVC entry points
if (!hasExplicitCallingConv(T)) {
if (isDefaultStdCall(FD, *this)) {
if (FT->getCallConv() != CC_X86StdCall) {
@@ -13674,12 +13735,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), Args);
if (RecoveryExpr.get())
VDecl->setInit(RecoveryExpr.get());
- // In general, for error recovery purposes, the initalizer doesn't play
+ // In general, for error recovery purposes, the initializer doesn't play
// part in the valid bit of the declaration. There are a few exceptions:
// 1) if the var decl has a deduced auto type, and the type cannot be
// deduced by an invalid initializer;
- // 2) if the var decl is decompsition decl with a non-deduced type, and
- // the initialization fails (e.g. `int [a] = {1, 2};`);
+ // 2) if the var decl is a decomposition decl with a non-deduced type,
+ // and the initialization fails (e.g. `int [a] = {1, 2};`);
// Case 1) was already handled elsewhere.
if (isa<DecompositionDecl>(VDecl)) // Case 2)
VDecl->setInvalidDecl();
@@ -13897,9 +13958,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
}
} else if (VDecl->isFileVarDecl()) {
// In C, extern is typically used to avoid tentative definitions when
- // declaring variables in headers, but adding an intializer makes it a
+ // declaring variables in headers, but adding an initializer makes it a
// definition. This is somewhat confusing, so GCC and Clang both warn on it.
- // In C++, extern is often used to give implictly static const variables
+ // In C++, extern is often used to give implicitly static const variables
// external linkage, so don't warn in that case. If selectany is present,
// this might be header code intended for C and C++ inclusion, so apply the
// C++ rules.
@@ -14093,7 +14154,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
return;
}
}
- // The declaration is unitialized, no need for further checks.
+ // The declaration is uninitialized, no need for further checks.
return;
}
@@ -14911,53 +14972,53 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
DeclaratorDecl *FirstNonDeducedAutoInGroup = nullptr;
bool DiagnosedNonDeducedAuto = false;
- for (unsigned i = 0, e = Group.size(); i != e; ++i) {
- if (Decl *D = Group[i]) {
- // Check if the Decl has been declared in '#pragma omp declare target'
- // directive and has static storage duration.
- if (auto *VD = dyn_cast<VarDecl>(D);
- LangOpts.OpenMP && VD && VD->hasAttr<OMPDeclareTargetDeclAttr>() &&
- VD->hasGlobalStorage())
- OpenMP().ActOnOpenMPDeclareTargetInitializer(D);
- // For declarators, there are some additional syntactic-ish checks we need
- // to perform.
- if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
- if (!FirstDeclaratorInGroup)
- FirstDeclaratorInGroup = DD;
- if (!FirstDecompDeclaratorInGroup)
- FirstDecompDeclaratorInGroup = dyn_cast<DecompositionDecl>(D);
- if (!FirstNonDeducedAutoInGroup && DS.hasAutoTypeSpec() &&
- !hasDeducedAuto(DD))
- FirstNonDeducedAutoInGroup = DD;
-
- if (FirstDeclaratorInGroup != DD) {
- // A decomposition declaration cannot be combined with any other
- // declaration in the same group.
- if (FirstDecompDeclaratorInGroup && !DiagnosedMultipleDecomps) {
- Diag(FirstDecompDeclaratorInGroup->getLocation(),
- diag::err_decomp_decl_not_alone)
- << FirstDeclaratorInGroup->getSourceRange()
- << DD->getSourceRange();
- DiagnosedMultipleDecomps = true;
- }
+ for (Decl *D : Group) {
+ if (!D)
+ continue;
+ // Check if the Decl has been declared in '#pragma omp declare target'
+ // directive and has static storage duration.
+ if (auto *VD = dyn_cast<VarDecl>(D);
+ LangOpts.OpenMP && VD && VD->hasAttr<OMPDeclareTargetDeclAttr>() &&
+ VD->hasGlobalStorage())
+ OpenMP().ActOnOpenMPDeclareTargetInitializer(D);
+ // For declarators, there are some additional syntactic-ish checks we need
+ // to perform.
+ if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (!FirstDeclaratorInGroup)
+ FirstDeclaratorInGroup = DD;
+ if (!FirstDecompDeclaratorInGroup)
+ FirstDecompDeclaratorInGroup = dyn_cast<DecompositionDecl>(D);
+ if (!FirstNonDeducedAutoInGroup && DS.hasAutoTypeSpec() &&
+ !hasDeducedAuto(DD))
+ FirstNonDeducedAutoInGroup = DD;
+
+ if (FirstDeclaratorInGroup != DD) {
+ // A decomposition declaration cannot be combined with any other
+ // declaration in the same group.
+ if (FirstDecompDeclaratorInGroup && !DiagnosedMultipleDecomps) {
+ Diag(FirstDecompDeclaratorInGroup->getLocation(),
+ diag::err_decomp_decl_not_alone)
+ << FirstDeclaratorInGroup->getSourceRange()
+ << DD->getSourceRange();
+ DiagnosedMultipleDecomps = true;
+ }
- // A declarator that uses 'auto' in any way other than to declare a
- // variable with a deduced type cannot be combined with any other
- // declarator in the same group.
- if (FirstNonDeducedAutoInGroup && !DiagnosedNonDeducedAuto) {
- Diag(FirstNonDeducedAutoInGroup->getLocation(),
- diag::err_auto_non_deduced_not_alone)
- << FirstNonDeducedAutoInGroup->getType()
- ->hasAutoForTrailingReturnType()
- << FirstDeclaratorInGroup->getSourceRange()
- << DD->getSourceRange();
- DiagnosedNonDeducedAuto = true;
- }
+ // A declarator that uses 'auto' in any way other than to declare a
+ // variable with a deduced type cannot be combined with any other
+ // declarator in the same group.
+ if (FirstNonDeducedAutoInGroup && !DiagnosedNonDeducedAuto) {
+ Diag(FirstNonDeducedAutoInGroup->getLocation(),
+ diag::err_auto_non_deduced_not_alone)
+ << FirstNonDeducedAutoInGroup->getType()
+ ->hasAutoForTrailingReturnType()
+ << FirstDeclaratorInGroup->getSourceRange()
+ << DD->getSourceRange();
+ DiagnosedNonDeducedAuto = true;
}
}
-
- Decls.push_back(D);
}
+
+ Decls.push_back(D);
}
if (DeclSpec::isDeclRep(DS.getTypeSpecType())) {
@@ -16324,7 +16385,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
FSI->ObjCWarnForNoDesignatedInitChain = false;
}
if (FSI->ObjCWarnForNoInitDelegation) {
- // Don't issue this warning for unavaialable inits.
+ // Don't issue this warning for unavailable inits.
if (!MD->isUnavailable())
Diag(MD->getLocation(),
diag::warn_objc_secondary_init_missing_init_call);
@@ -17876,7 +17937,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
SkipBody->Previous = Def;
makeMergedDefinitionVisible(Hidden);
// Carry on and handle it like a normal definition. We'll
- // skip starting the definitiion later.
+ // skip starting the definition later.
}
} else if (!IsExplicitSpecializationAfterInstantiation) {
// A redeclaration in function prototype scope in C isn't
@@ -18333,6 +18394,15 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
if (NumInitMethods > 1 || !Def->hasInitMethod())
Diag(RD->getLocation(), diag::err_sycl_special_type_num_init_method);
}
+
+ // If we're defining a dynamic class in a module interface unit, we always
+ // need to produce the vtable for it even if the vtable is not used in the
+ // current TU.
+ //
+ // The case that the current class is not dynamic is handled in
+ // MarkVTableUsed.
+ if (getCurrentModule() && getCurrentModule()->isInterfaceOrPartition())
+ MarkVTableUsed(RD->getLocation(), RD, /*DefinitionRequired=*/true);
}
// Exit this scope of this tag's definition.
@@ -20475,7 +20545,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(const FunctionDecl *FD,
} else if (LangOpts.OpenMP > 45) {
// In OpenMP host compilation prior to 5.0 everything was an emitted host
// function. In 5.0, no_host was introduced which might cause a function to
- // be ommitted.
+ // be omitted.
std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
if (DevTy)
@@ -20518,3 +20588,62 @@ bool Sema::shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee) {
return LangOpts.CUDA && !LangOpts.CUDAIsDevice &&
CUDA().IdentifyTarget(Callee) == CUDAFunctionTarget::Global;
}
+
+// Report a failure to merge function effects between declarations due to a
+// conflict.
+void Sema::diagnoseFunctionEffectMergeConflicts(
+ const FunctionEffectSet::Conflicts &Errs, SourceLocation NewLoc,
+ SourceLocation OldLoc) {
+ for (const FunctionEffectSet::Conflict &Conflict : Errs) {
+ Diag(NewLoc, diag::warn_conflicting_func_effects)
+ << Conflict.Kept.description() << Conflict.Rejected.description();
+ Diag(OldLoc, diag::note_previous_declaration);
+ }
+}
+
+// Warn and return true if adding an effect to a set would create a conflict.
+bool Sema::diagnoseConflictingFunctionEffect(
+ const FunctionEffectsRef &FX, const FunctionEffectWithCondition &NewEC,
+ SourceLocation NewAttrLoc) {
+ // If the new effect has a condition, we can't detect conflicts until the
+ // condition is resolved.
+ if (NewEC.Cond.getCondition() != nullptr)
+ return false;
+
+ // Diagnose the new attribute as incompatible with a previous one.
+ auto Incompatible = [&](const FunctionEffectWithCondition &PrevEC) {
+ Diag(NewAttrLoc, diag::err_attributes_are_not_compatible)
+ << ("'" + NewEC.description() + "'")
+ << ("'" + PrevEC.description() + "'") << false;
+ // We don't necessarily have the location of the previous attribute,
+ // so no note.
+ return true;
+ };
+
+ // Compare against previous attributes.
+ FunctionEffect::Kind NewKind = NewEC.Effect.kind();
+
+ for (const FunctionEffectWithCondition &PrevEC : FX) {
+ // Again, can't check yet when the effect is conditional.
+ if (PrevEC.Cond.getCondition() != nullptr)
+ continue;
+
+ FunctionEffect::Kind PrevKind = PrevEC.Effect.kind();
+ // Note that we allow PrevKind == NewKind; it's redundant and ignored.
+
+ if (PrevEC.Effect.oppositeKind() == NewKind)
+ return Incompatible(PrevEC);
+
+ // A new allocating is incompatible with a previous nonblocking.
+ if (PrevKind == FunctionEffect::Kind::NonBlocking &&
+ NewKind == FunctionEffect::Kind::Allocating)
+ return Incompatible(PrevEC);
+
+ // A new nonblocking is incompatible with a previous allocating.
+ if (PrevKind == FunctionEffect::Kind::Allocating &&
+ NewKind == FunctionEffect::Kind::NonBlocking)
+ return Incompatible(PrevEC);
+ }
+
+ return false;
+}