if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// White-list anything with an __attribute__((unused)) type.
- QualType Ty = VD->getType();
+ const auto *Ty = VD->getType().getTypePtr();
// Only look at the outermost level of typedef.
if (const TypedefType *TT = Ty->getAs<TypedefType>()) {
if (Ty->isIncompleteType() || Ty->isDependentType())
return false;
+ // Look at the element type to ensure that the warning behaviour is
+ // consistent for both scalars and arrays.
+ Ty = Ty->getBaseElementTypeUnsafe();
+
if (const TagType *TT = Ty->getAs<TagType>()) {
const TagDecl *Tag = TT->getDecl();
if (Tag->hasAttr<UnusedAttr>())
return nullptr;
}
- if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(ID)) {
+ if (!ForRedeclaration &&
+ (Context.BuiltinInfo.isPredefinedLibFunction(ID) ||
+ Context.BuiltinInfo.isHeaderDependentFunction(ID))) {
Diag(Loc, diag::ext_implicit_lib_function_decl)
<< Context.BuiltinInfo.getName(ID) << R;
if (Context.BuiltinInfo.getHeaderName(ID) &&
NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(),
&S.Context.Idents.get(AA->getSpelling()),
AttrSpellingListIndex);
- else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr))
+ else if (S.getLangOpts().CUDA && isa<FunctionDecl>(D) &&
+ (isa<CUDAHostAttr>(Attr) || isa<CUDADeviceAttr>(Attr) ||
+ isa<CUDAGlobalAttr>(Attr))) {
+ // CUDA target attributes are part of function signature for
+ // overloading purposes and must not be merged.
+ return false;
+ } else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr))
NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex);
else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr))
NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex);
}
if (getLangOpts().CPlusPlus) {
- // (C++98 13.1p2):
+ // C++1z [over.load]p2
// Certain function declarations cannot be overloaded:
- // -- Function declarations that differ only in the return type
- // cannot be overloaded.
+ // -- Function declarations that differ only in the return type,
+ // the exception specification, or both cannot be overloaded.
+
+ // Check the exception specifications match. This may recompute the type of
+ // both Old and New if it resolved exception specifications, so grab the
+ // types again after this. Because this updates the type, we do this before
+ // any of the other checks below, which may update the "de facto" NewQType
+ // but do not necessarily update the type of New.
+ if (CheckEquivalentExceptionSpec(Old, New))
+ return true;
+ OldQType = Context.getCanonicalType(Old->getType());
+ NewQType = Context.getCanonicalType(New->getType());
// Go back to the type source info to compare the declared return types,
// per C++1y [dcl.type.auto]p13:
(New->getTypeSourceInfo()
? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
: NewType)->getReturnType();
- QualType ResQT;
if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) &&
!((NewQType->isDependentType() || OldQType->isDependentType()) &&
New->isLocalExternDecl())) {
+ QualType ResQT;
if (NewDeclaredReturnType->isObjCObjectPointerType() &&
OldDeclaredReturnType->isObjCObjectPointerType())
ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
// noreturn should now match unless the old type info didn't have it.
QualType OldQTypeForComparison = OldQType;
if (!OldTypeInfo.getNoReturn() && NewTypeInfo.getNoReturn()) {
- assert(OldQType == QualType(OldType, 0));
+ auto *OldType = OldQType->castAs<FunctionProtoType>();
const FunctionType *OldTypeForComparison
= Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true));
OldQTypeForComparison = QualType(OldTypeForComparison, 0);
}
// C++ doesn't have tentative definitions, so go right ahead and check here.
- VarDecl *Def;
if (getLangOpts().CPlusPlus &&
- New->isThisDeclarationADefinition() == VarDecl::Definition &&
- (Def = Old->getDefinition())) {
- NamedDecl *Hidden = nullptr;
- if (!hasVisibleDefinition(Def, &Hidden) &&
- (New->getFormalLinkage() == InternalLinkage ||
- New->getDescribedVarTemplate() ||
- New->getNumTemplateParameterLists() ||
- New->getDeclContext()->isDependentContext())) {
- // The previous definition is hidden, and multiple definitions are
- // permitted (in separate TUs). Form another definition of it.
- } else if (Old->isStaticDataMember() &&
- Old->getCanonicalDecl()->isInline() &&
- Old->getCanonicalDecl()->isConstexpr()) {
+ New->isThisDeclarationADefinition() == VarDecl::Definition) {
+ if (Old->isStaticDataMember() && Old->getCanonicalDecl()->isInline() &&
+ Old->getCanonicalDecl()->isConstexpr()) {
// This definition won't be a definition any more once it's been merged.
Diag(New->getLocation(),
diag::warn_deprecated_redundant_constexpr_static_def);
- } else {
- Diag(New->getLocation(), diag::err_redefinition) << New;
- Diag(Def->getLocation(), diag::note_previous_definition);
- New->setInvalidDecl();
- return;
+ } else if (VarDecl *Def = Old->getDefinition()) {
+ if (checkVarDeclRedefinition(Def, New))
+ return;
}
}
New->setImplicitlyInline();
}
+/// 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) {
+ if (!hasVisibleDefinition(Old) &&
+ (New->getFormalLinkage() == InternalLinkage ||
+ New->isInline() ||
+ New->getDescribedVarTemplate() ||
+ New->getNumTemplateParameterLists() ||
+ New->getDeclContext()->isDependentContext())) {
+ // The previous definition is hidden, and multiple definitions are
+ // permitted (in separate TUs). Demote this to a declaration.
+ New->demoteThisDefinitionToDeclaration();
+
+ // Make the canonical definition visible.
+ if (auto *OldTD = Old->getDescribedVarTemplate())
+ makeMergedDefinitionVisible(OldTD, New->getLocation());
+ makeMergedDefinitionVisible(Old, New->getLocation());
+ return false;
+ } else {
+ Diag(New->getLocation(), diag::err_redefinition) << New;
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ New->setInvalidDecl();
+ return true;
+ }
+}
+
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
Decl *
NamedDecl *NewDecl,
bool IsSpecialization,
bool IsDefinition) {
+ if (OldDecl->isInvalidDecl())
+ return;
+
if (TemplateDecl *OldTD = dyn_cast<TemplateDecl>(OldDecl)) {
OldDecl = OldTD->getTemplatedDecl();
if (!IsSpecialization)
return false;
// Okay, go ahead and call the relatively-more-expensive function.
-
-#ifndef NDEBUG
- // AST quite reasonably asserts that it's working on a function
- // definition. We don't really have a way to tell it that we're
- // currently defining the function, so just lie to it in +Asserts
- // builds. This is an awful hack.
- FD->setLazyBody(1);
-#endif
-
- bool isC99Inline =
- S.Context.GetGVALinkageForFunction(FD) == GVA_AvailableExternally;
-
-#ifndef NDEBUG
- FD->setLazyBody(0);
-#endif
-
- return isC99Inline;
+ return S.Context.GetGVALinkageForFunction(FD) == GVA_AvailableExternally;
}
/// Determine whether a variable is extern "C" prior to attaching
return nullptr;
}
- // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument.
- // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function
- // argument.
- if (getLangOpts().OpenCL && (R->isImageType() || R->isPipeType())) {
- Diag(D.getIdentifierLoc(),
- diag::err_opencl_type_can_only_be_used_as_function_parameter)
- << R;
- D.setInvalidType();
- return nullptr;
- }
-
- DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
- StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
-
- // dllimport globals without explicit storage class are treated as extern. We
- // have to change the storage class this early to get the right DeclContext.
- if (SC == SC_None && !DC->isRecord() &&
- hasParsedAttr(S, D, AttributeList::AT_DLLImport) &&
- !hasParsedAttr(S, D, AttributeList::AT_DLLExport))
- SC = SC_Extern;
+ if (getLangOpts().OpenCL) {
+ // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument.
+ // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function
+ // argument.
+ if (R->isImageType() || R->isPipeType()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_opencl_type_can_only_be_used_as_function_parameter)
+ << R;
+ D.setInvalidType();
+ return nullptr;
+ }
- DeclContext *OriginalDC = DC;
- bool IsLocalExternDecl = SC == SC_Extern &&
- adjustContextForLocalExternDecl(DC);
+ // OpenCL v1.2 s6.9.r:
+ // The event type cannot be used to declare a program scope variable.
+ // OpenCL v2.0 s6.9.q:
+ // The clk_event_t and reserve_id_t types cannot be declared in program scope.
+ if (NULL == S->getParent()) {
+ if (R->isReserveIDT() || R->isClkEventT() || R->isEventT()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_invalid_type_for_program_scope_var) << R;
+ D.setInvalidType();
+ return nullptr;
+ }
+ }
- if (getLangOpts().OpenCL) {
// OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
QualType NR = R;
while (NR->isPointerType()) {
D.setInvalidType();
}
}
+
+ // OpenCL v1.2 s6.9.b p4:
+ // The sampler type cannot be used with the __local and __global address
+ // space qualifiers.
+ if (R->isSamplerT() && (R.getAddressSpace() == LangAS::opencl_local ||
+ R.getAddressSpace() == LangAS::opencl_global)) {
+ Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace);
+ }
+
+ // OpenCL v1.2 s6.9.r:
+ // The event type cannot be used with the __local, __constant and __global
+ // address space qualifiers.
+ if (R->isEventT()) {
+ if (R.getAddressSpace()) {
+ Diag(D.getLocStart(), diag::err_event_t_addr_space_qual);
+ D.setInvalidType();
+ }
+ }
}
+ DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
+ StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
+
+ // dllimport globals without explicit storage class are treated as extern. We
+ // have to change the storage class this early to get the right DeclContext.
+ if (SC == SC_None && !DC->isRecord() &&
+ hasParsedAttr(S, D, AttributeList::AT_DLLImport) &&
+ !hasParsedAttr(S, D, AttributeList::AT_DLLExport))
+ SC = SC_Extern;
+
+ DeclContext *OriginalDC = DC;
+ bool IsLocalExternDecl = SC == SC_Extern &&
+ adjustContextForLocalExternDecl(DC);
+
if (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
}
}
- if (getLangOpts().OpenCL) {
- // OpenCL v1.2 s6.9.b p4:
- // The sampler type cannot be used with the __local and __global address
- // space qualifiers.
- if (R->isSamplerT() && (R.getAddressSpace() == LangAS::opencl_local ||
- R.getAddressSpace() == LangAS::opencl_global)) {
- Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace);
- }
-
- // OpenCL 1.2 spec, p6.9 r:
- // The event type cannot be used to declare a program scope variable.
- // The event type cannot be used with the __local, __constant and __global
- // address space qualifiers.
- if (R->isEventT()) {
- if (S->getParent() == nullptr) {
- Diag(D.getLocStart(), diag::err_event_t_global_var);
- D.setInvalidType();
- }
-
- if (R.getAddressSpace()) {
- Diag(D.getLocStart(), diag::err_event_t_addr_space_qual);
- D.setInvalidType();
- }
- }
- }
-
bool IsExplicitSpecialization = false;
bool IsVariableTemplateSpecialization = false;
bool IsPartialSpecialization = false;
return OldDC->isFileContext() ? SDK_Global : SDK_Local;
}
+/// Return the location of the capture if the given lambda captures the given
+/// variable \p VD, or an invalid source location otherwise.
+static SourceLocation getCaptureLocation(const LambdaScopeInfo *LSI,
+ const VarDecl *VD) {
+ for (const LambdaScopeInfo::Capture &Capture : LSI->Captures) {
+ if (Capture.isVariableCapture() && Capture.getVariable() == VD)
+ return Capture.getLocation();
+ }
+ return SourceLocation();
+}
+
/// \brief Diagnose variable or built-in function shadowing. Implements
/// -Wshadow.
///
DeclContext *OldDC = ShadowedDecl->getDeclContext();
+ unsigned WarningDiag = diag::warn_decl_shadow;
+ SourceLocation CaptureLoc;
+ if (isa<VarDecl>(ShadowedDecl) && NewDC && isa<CXXMethodDecl>(NewDC)) {
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(NewDC->getParent())) {
+ if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) {
+ if (RD->getLambdaCaptureDefault() == LCD_None) {
+ // Try to avoid warnings for lambdas with an explicit capture list.
+ const auto *LSI = cast<LambdaScopeInfo>(getCurFunction());
+ // Warn only when the lambda captures the shadowed decl explicitly.
+ CaptureLoc = getCaptureLocation(LSI, cast<VarDecl>(ShadowedDecl));
+ if (CaptureLoc.isInvalid())
+ WarningDiag = diag::warn_decl_shadow_uncaptured_local;
+ } else {
+ // Remember that this was shadowed so we can avoid the warning if the
+ // shadowed decl isn't captured and the warning settings allow it.
+ cast<LambdaScopeInfo>(getCurFunction())
+ ->ShadowingDecls.push_back({D, cast<VarDecl>(ShadowedDecl)});
+ return;
+ }
+ }
+ }
+ }
+
// Only warn about certain kinds of shadowing for class members.
if (NewDC && NewDC->isRecord()) {
// In particular, don't warn about shadowing non-class members.
if (getSourceManager().isInSystemMacro(R.getNameLoc()))
return;
ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC);
- Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC;
+ Diag(R.getNameLoc(), WarningDiag) << Name << Kind << OldDC;
+ if (!CaptureLoc.isInvalid())
+ Diag(CaptureLoc, diag::note_var_explicitly_captured_here)
+ << Name << /*explicitly*/ 1;
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
}
+/// Diagnose shadowing for variables shadowed in the lambda record \p LambdaRD
+/// when these variables are captured by the lambda.
+void Sema::DiagnoseShadowingLambdaDecls(const LambdaScopeInfo *LSI) {
+ for (const auto &Shadow : LSI->ShadowingDecls) {
+ const VarDecl *ShadowedDecl = Shadow.ShadowedDecl;
+ // Try to avoid the warning when the shadowed decl isn't captured.
+ SourceLocation CaptureLoc = getCaptureLocation(LSI, ShadowedDecl);
+ const DeclContext *OldDC = ShadowedDecl->getDeclContext();
+ Diag(Shadow.VD->getLocation(), CaptureLoc.isInvalid()
+ ? diag::warn_decl_shadow_uncaptured_local
+ : diag::warn_decl_shadow)
+ << Shadow.VD->getDeclName()
+ << computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC;
+ if (!CaptureLoc.isInvalid())
+ Diag(CaptureLoc, diag::note_var_explicitly_captured_here)
+ << Shadow.VD->getDeclName() << /*explicitly*/ 0;
+ Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
+ }
+}
+
/// \brief Check -Wshadow without the advantage of a previous lookup.
void Sema::CheckShadow(Scope *S, VarDecl *D) {
if (Diags.isIgnored(diag::warn_decl_shadow, D->getLocation()))
NewVD->setInvalidDecl();
return;
}
- // OpenCL v2.0 s6.12.5 - Blocks with variadic arguments are not supported.
- // TODO: this check is not enough as it doesn't diagnose the typedef
- const BlockPointerType *BlkTy = T->getAs<BlockPointerType>();
- const FunctionProtoType *FTy =
- BlkTy->getPointeeType()->getAs<FunctionProtoType>();
- if (FTy && FTy->isVariadic()) {
- Diag(NewVD->getLocation(), diag::err_opencl_block_proto_variadic)
- << T << NewVD->getSourceRange();
- NewVD->setInvalidDecl();
- return;
- }
}
// OpenCL v1.2 s6.5 - All program scope variables must be declared in the
// __constant address space.
RecordKernelParam
};
-static OpenCLParamType getOpenCLKernelParameterType(QualType PT) {
+static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
if (PT->isPointerType()) {
QualType PointeeType = PT->getPointeeType();
if (PointeeType->isPointerType())
if (PT->isEventT())
return InvalidKernelParam;
- if (PT->isHalfType())
+ // OpenCL extension spec v1.2 s9.5:
+ // This extension adds support for half scalar and vector types as built-in
+ // types that can be used for arithmetic operations, conversions etc.
+ if (!S.getOpenCLOptions().cl_khr_fp16 && PT->isHalfType())
return InvalidKernelParam;
if (PT->isRecordType())
if (ValidTypes.count(PT.getTypePtr()))
return;
- switch (getOpenCLKernelParameterType(PT)) {
+ switch (getOpenCLKernelParameterType(S, PT)) {
case PtrPtrKernelParam:
// OpenCL v1.2 s6.9.a:
// A kernel function argument cannot be declared as a
// OpenCL v1.2 s6.8 n:
// A kernel function argument cannot be declared
// of event_t type.
- S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT;
+ // Do not diagnose half type since it is diagnosed as invalid argument
+ // type for any function elsewhere.
+ if (!PT->isHalfType())
+ S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT;
D.setInvalidType();
return;
if (ValidTypes.count(QT.getTypePtr()))
continue;
- OpenCLParamType ParamType = getOpenCLKernelParameterType(QT);
+ OpenCLParamType ParamType = getOpenCLKernelParameterType(S, QT);
if (ParamType == ValidKernelParam)
continue;
ProcessDeclAttributes(S, NewFD, D);
if (getLangOpts().CUDA)
- maybeAddCUDAHostDeviceAttrs(S, NewFD, Previous);
+ maybeAddCUDAHostDeviceAttrs(NewFD, Previous);
if (getLangOpts().OpenCL) {
// OpenCL v1.1 s6.5: Using an address space qualifier in a function return
? cast<NamedDecl>(FunctionTemplate)
: NewFD);
- if (isFriend && D.isRedeclaration()) {
+ if (isFriend && NewFD->getPreviousDecl()) {
AccessSpecifier Access = AS_public;
if (!NewFD->isInvalidDecl())
Access = NewFD->getPreviousDecl()->getAccess();
return NewFD;
}
+/// \brief Checks if the new declaration declared in dependent context must be
+/// put in the same redeclaration chain as the specified declaration.
+///
+/// \param D Declaration that is checked.
+/// \param PrevDecl Previous declaration found with proper lookup method for the
+/// same declaration name.
+/// \returns True if D must be added to the redeclaration chain which PrevDecl
+/// belongs to.
+///
+bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) {
+ // Any declarations should be put into redeclaration chains except for
+ // friend declaration in a dependent context that names a function in
+ // namespace scope.
+ //
+ // This allows to compile code like:
+ //
+ // void func();
+ // template<typename T> class C1 { friend void func() { } };
+ // template<typename T> class C2 { friend void func() { } };
+ //
+ // This code snippet is a valid code unless both templates are instantiated.
+ return !(D->getLexicalDeclContext()->isDependentContext() &&
+ D->getDeclContext()->isFileContext() &&
+ D->getFriendObjectKind() != Decl::FOK_None);
+}
+
/// \brief Perform semantic checking of a new function declaration.
///
/// Performs semantic analysis of the new function declaration
}
} else {
- // This needs to happen first so that 'inline' propagates.
- NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
-
- if (isa<CXXMethodDecl>(NewFD))
- NewFD->setAccess(OldDecl->getAccess());
+ if (shouldLinkDependentDeclWithPrevious(NewFD, OldDecl)) {
+ // This needs to happen first so that 'inline' propagates.
+ NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
+ if (isa<CXXMethodDecl>(NewFD))
+ NewFD->setAccess(OldDecl->getAccess());
+ }
}
}
LookupPredefedObjCSuperType(*this, S, NewFD->getIdentifier());
QualType T = Context.GetBuiltinType(BuiltinID, Error);
if (!T.isNull() && !Context.hasSameType(T, NewFD->getType())) {
- // The type of this function differs from the type of the builtin,
- // so forget about the builtin entirely.
- Context.BuiltinInfo.forgetBuiltin(BuiltinID, Context.Idents);
+ auto WithoutExceptionSpec = [&](QualType T) -> QualType {
+ auto *Proto = T->getAs<FunctionProtoType>();
+ if (!Proto)
+ return T;
+ return Context.getFunctionType(
+ Proto->getReturnType(), Proto->getParamTypes(),
+ Proto->getExtProtoInfo().withExceptionSpec(EST_None));
+ };
+
+ // If the type of the builtin differs only in its exception
+ // specification, that's OK.
+ // FIXME: If the types do differ in this way, it would be better to
+ // retain the 'noexcept' form of the type.
+ if (!getLangOpts().CPlusPlus1z ||
+ !Context.hasSameType(WithoutExceptionSpec(T),
+ WithoutExceptionSpec(NewFD->getType())))
+ // The type of this function differs from the type of the builtin,
+ // so forget about the builtin entirely.
+ Context.BuiltinInfo.forgetBuiltin(BuiltinID, Context.Idents);
}
}
!R->isObjCObjectPointerType())
Diag(NewFD->getLocation(), diag::warn_return_value_udt) << NewFD << R;
}
+
+ // C++1z [dcl.fct]p6:
+ // [...] whether the function has a non-throwing exception-specification
+ // [is] part of the function type
+ //
+ // This results in an ABI break between C++14 and C++17 for functions whose
+ // declared type includes an exception-specification in a parameter or
+ // return type. (Exception specifications on the function itself are OK in
+ // most cases, and exception specifications are not permitted in most other
+ // contexts where they could make it into a mangling.)
+ if (!getLangOpts().CPlusPlus1z && !NewFD->getPrimaryTemplate()) {
+ auto HasNoexcept = [&](QualType T) -> bool {
+ // Strip off declarator chunks that could be between us and a function
+ // type. We don't need to look far, exception specifications are very
+ // restricted prior to C++17.
+ if (auto *RT = T->getAs<ReferenceType>())
+ T = RT->getPointeeType();
+ else if (T->isAnyPointerType())
+ T = T->getPointeeType();
+ else if (auto *MPT = T->getAs<MemberPointerType>())
+ T = MPT->getPointeeType();
+ if (auto *FPT = T->getAs<FunctionProtoType>())
+ if (FPT->isNothrow(Context))
+ return true;
+ return false;
+ };
+
+ auto *FPT = NewFD->getType()->castAs<FunctionProtoType>();
+ bool AnyNoexcept = HasNoexcept(FPT->getReturnType());
+ for (QualType T : FPT->param_types())
+ AnyNoexcept |= HasNoexcept(T);
+ if (AnyNoexcept)
+ Diag(NewFD->getLocation(),
+ diag::warn_cxx1z_compat_exception_spec_in_signature)
+ << NewFD;
+ }
}
return Redeclaration;
}
VDecl->setInvalidDecl();
}
+ // If adding the initializer will turn this declaration into a definition,
+ // and we already have a definition for this variable, diagnose or otherwise
+ // handle the situation.
VarDecl *Def;
if ((Def = VDecl->getDefinition()) && Def != VDecl &&
- (!VDecl->isStaticDataMember() || VDecl->isOutOfLine())) {
- NamedDecl *Hidden = nullptr;
- if (!hasVisibleDefinition(Def, &Hidden) &&
- (VDecl->getFormalLinkage() == InternalLinkage ||
- VDecl->getDescribedVarTemplate() ||
- VDecl->getNumTemplateParameterLists() ||
- VDecl->getDeclContext()->isDependentContext())) {
- // The previous definition is hidden, and multiple definitions are
- // permitted (in separate TUs). Form another definition of it.
- } else {
- Diag(VDecl->getLocation(), diag::err_redefinition)
- << VDecl->getDeclName();
- Diag(Def->getLocation(), diag::note_previous_definition);
- VDecl->setInvalidDecl();
- return;
- }
- }
+ (!VDecl->isStaticDataMember() || VDecl->isOutOfLine()) &&
+ !VDecl->isThisDeclarationADemotedDefinition() &&
+ checkVarDeclRedefinition(Def, VDecl))
+ return;
if (getLangOpts().CPlusPlus) {
// C++ [class.static.data]p4
// Perform the initialization.
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
if (!VDecl->isInvalidDecl()) {
+ // Handle errors like: int a({0})
+ if (CXXDirectInit && CXXDirectInit->getNumExprs() == 1 &&
+ !canInitializeWithParenthesizedList(VDecl->getType()))
+ if (auto IList = dyn_cast<InitListExpr>(CXXDirectInit->getExpr(0))) {
+ Diag(VDecl->getLocation(), diag::err_list_init_in_parens)
+ << VDecl->getType() << CXXDirectInit->getSourceRange()
+ << FixItHint::CreateRemoval(CXXDirectInit->getLocStart())
+ << FixItHint::CreateRemoval(CXXDirectInit->getLocEnd());
+ Init = IList;
+ CXXDirectInit = nullptr;
+ }
+
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
InitializationKind Kind =
DirectInit
// though.
}
+/// Checks if an object of the given type can be initialized with parenthesized
+/// init-list.
+///
+/// \param TargetType Type of object being initialized.
+///
+/// The function is used to detect wrong initializations, such as 'int({0})'.
+///
+bool Sema::canInitializeWithParenthesizedList(QualType TargetType) {
+ return TargetType->isDependentType() || TargetType->isRecordType() ||
+ TargetType->getContainedAutoType();
+}
+
void Sema::ActOnUninitializedDecl(Decl *RealDecl,
bool TypeMayContainAuto) {
// If there is no declaration, there was an error parsing it. Just ignore it.
// C++11 [dcl.constexpr]p1: The constexpr specifier shall be applied only to
// the definition of a variable [...] or the declaration of a static data
// member.
- if (Var->isConstexpr() && !Var->isThisDeclarationADefinition()) {
+ if (Var->isConstexpr() && !Var->isThisDeclarationADefinition() &&
+ !Var->isThisDeclarationADemotedDefinition()) {
if (Var->isStaticDataMember()) {
// C++1z removes the relevant rule; the in-class declaration is always
// a definition there.
}
// All the following checks are C++ only.
- if (!getLangOpts().CPlusPlus) return;
+ if (!getLangOpts().CPlusPlus) {
+ // If this variable must be emitted, add it as an initializer for the
+ // current module.
+ if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty())
+ Context.addModuleInitializer(ModuleScopes.back().Module, var);
+ return;
+ }
if (auto *DD = dyn_cast<DecompositionDecl>(var))
CheckCompleteDecompositionDeclaration(DD);
if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl)) {
for (auto *BD : DD->bindings()) {
- if (ThisDecl->isInvalidDecl())
- BD->setInvalidDecl();
FinalizeDeclaration(BD);
}
}
// CUDA E.2.9.4: Within the body of a __device__ or __global__
// function, only __shared__ variables may be declared with
// static storage class.
- if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice &&
- (FD->hasAttr<CUDADeviceAttr>() || FD->hasAttr<CUDAGlobalAttr>()) &&
- !VD->hasAttr<CUDASharedAttr>()) {
- Diag(VD->getLocation(), diag::err_device_static_local_var);
+ if (getLangOpts().CUDA && !VD->hasAttr<CUDASharedAttr>() &&
+ CUDADiagIfDeviceCode(VD->getLocation(),
+ diag::err_device_static_local_var)
+ << CurrentCUDATarget())
VD->setInvalidDecl();
- }
}
}
if (Init && VD->hasGlobalStorage()) {
if (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() ||
VD->hasAttr<CUDASharedAttr>()) {
- assert((!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>()));
+ assert(!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>());
bool AllowedInit = false;
if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init))
AllowedInit =
return D;
}
+ // Mark this function as "will have a body eventually". This lets users to
+ // call e.g. isInlineDefinitionExternallyVisible while we're still parsing
+ // this function.
+ FD->setWillHaveBody();
+
// If we are instantiating a generic lambda call operator, push
// a LambdaScopeInfo onto the function stack. But use the information
// that's already been calculated (ActOnLambdaExpr) to prime the current
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
- if (getLangOpts().Coroutines && !getCurFunction()->CoroutineStmts.empty())
+ if (getLangOpts().CoroutinesTS && !getCurFunction()->CoroutineStmts.empty())
CheckCompletedCoroutineBody(FD, Body);
if (FD) {
return Tag == TTK_Struct || Tag == TTK_Class || Tag == TTK_Interface;
}
+Sema::NonTagKind Sema::getNonTagTypeDeclKind(const Decl *PrevDecl) {
+ if (isa<TypedefDecl>(PrevDecl))
+ return NTK_Typedef;
+ else if (isa<TypeAliasDecl>(PrevDecl))
+ return NTK_TypeAlias;
+ else if (isa<ClassTemplateDecl>(PrevDecl))
+ return NTK_Template;
+ else if (isa<TypeAliasTemplateDecl>(PrevDecl))
+ return NTK_TypeAliasTemplate;
+ else if (isa<TemplateTemplateParmDecl>(PrevDecl))
+ return NTK_TemplateTemplateArgument;
+ return NTK_Unknown;
+}
+
/// \brief Determine whether a tag with a given kind is acceptable
/// as a redeclaration of the given tag declaration.
///
DeclContext *SearchDC = CurContext;
DeclContext *DC = CurContext;
bool isStdBadAlloc = false;
+ bool isStdAlignValT = false;
RedeclarationKind Redecl = ForRedeclaration;
if (TUK == TUK_Friend || TUK == TUK_Reference)
}
if (getLangOpts().CPlusPlus && Name && DC && StdNamespace &&
- DC->Equals(getStdNamespace()) && Name->isStr("bad_alloc")) {
- // This is a declaration of or a reference to "std::bad_alloc".
- isStdBadAlloc = true;
+ DC->Equals(getStdNamespace())) {
+ if (Name->isStr("bad_alloc")) {
+ // This is a declaration of or a reference to "std::bad_alloc".
+ isStdBadAlloc = true;
- if (Previous.empty() && StdBadAlloc) {
- // std::bad_alloc has been implicitly declared (but made invisible to
- // name lookup). Fill in this implicit declaration as the previous
+ // If std::bad_alloc has been implicitly declared (but made invisible to
+ // name lookup), fill in this implicit declaration as the previous
// declaration, so that the declarations get chained appropriately.
- Previous.addDecl(getStdBadAlloc());
+ if (Previous.empty() && StdBadAlloc)
+ Previous.addDecl(getStdBadAlloc());
+ } else if (Name->isStr("align_val_t")) {
+ isStdAlignValT = true;
+ if (Previous.empty() && StdAlignValT)
+ Previous.addDecl(getStdAlignValT());
}
}
// (non-redeclaration) lookup.
if ((TUK == TUK_Reference || TUK == TUK_Friend) &&
!Previous.isForRedeclaration()) {
- unsigned Kind = 0;
- if (isa<TypedefDecl>(PrevDecl)) Kind = 1;
- else if (isa<TypeAliasDecl>(PrevDecl)) Kind = 2;
- else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 3;
- Diag(NameLoc, diag::err_tag_reference_non_tag) << Kind;
+ NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl);
+ Diag(NameLoc, diag::err_tag_reference_non_tag) << NTK;
Diag(PrevDecl->getLocation(), diag::note_declared_at);
Invalid = true;
// Diagnose implicit declarations introduced by elaborated types.
} else if (TUK == TUK_Reference || TUK == TUK_Friend) {
- unsigned Kind = 0;
- if (isa<TypedefDecl>(PrevDecl)) Kind = 1;
- else if (isa<TypeAliasDecl>(PrevDecl)) Kind = 2;
- else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 3;
- Diag(NameLoc, diag::err_tag_reference_conflict) << Kind;
+ NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl);
+ Diag(NameLoc, diag::err_tag_reference_conflict) << NTK;
Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
Invalid = true;
New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name,
cast_or_null<EnumDecl>(PrevDecl), ScopedEnum,
ScopedEnumUsesClassTag, !EnumUnderlying.isNull());
+
+ if (isStdAlignValT && (!StdAlignValT || getStdAlignValT()->isImplicit()))
+ StdAlignValT = cast<EnumDecl>(New);
+
// If this is an undefined enum, warn.
if (TUK != TUK_Definition && !Invalid) {
TagDecl *Def;
OwnedDecl = true;
// In C++, don't return an invalid declaration. We can't recover well from
// the cases where we make the type anonymous.
- return (Invalid && getLangOpts().CPlusPlus) ? nullptr : New;
+ if (Invalid && getLangOpts().CPlusPlus) {
+ if (New->isBeingDefined())
+ if (auto RD = dyn_cast<RecordDecl>(New))
+ RD->completeDefinition();
+ return nullptr;
+ } else {
+ return New;
+ }
}
void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
if (!Completed)
Record->completeDefinition();
+ // We may have deferred checking for a deleted destructor. Check now.
+ if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) {
+ auto *Dtor = CXXRecord->getDestructor();
+ if (Dtor && Dtor->isImplicit() &&
+ ShouldDeleteSpecialMember(Dtor, CXXDestructor))
+ SetDeclDeleted(Dtor, CXXRecord->getLocation());
+ }
+
if (Record->hasAttrs()) {
CheckAlignasUnderalignment(Record);
} else if (!M->IsExternC && ExternCLoc.isValid()) {
S.Diag(ImportLoc, diag::ext_module_import_in_extern_c)
<< M->getFullModuleName();
- S.Diag(ExternCLoc, diag::note_module_import_in_extern_c);
+ S.Diag(ExternCLoc, diag::note_extern_c_begins_here);
}
}
/// (if present).
Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
SourceLocation LBraceLoc) {
- // FIXME: C++ Modules TS:
+ ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc);
+
+ // C++ Modules TS draft:
// An export-declaration [...] shall not contain more than one
// export keyword.
//
// The intent here is that an export-declaration cannot appear within another
// export-declaration.
+ if (D->isExported())
+ Diag(ExportLoc, diag::err_export_within_export);
- ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc);
CurContext->addDecl(D);
PushDeclContext(S, D);
return D;
Decl *Sema::getObjCDeclContext() const {
return (dyn_cast_or_null<ObjCContainerDecl>(CurContext));
}
-
-AvailabilityResult Sema::getCurContextAvailability() const {
- const Decl *D = cast_or_null<Decl>(getCurObjCLexicalContext());
- if (!D)
- return AR_Available;
-
- // If we are within an Objective-C method, we should consult
- // both the availability of the method as well as the
- // enclosing class. If the class is (say) deprecated,
- // the entire method is considered deprecated from the
- // purpose of checking if the current context is deprecated.
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- AvailabilityResult R = MD->getAvailability();
- if (R != AR_Available)
- return R;
- D = MD->getClassInterface();
- }
- // If we are within an Objective-c @implementation, it
- // gets the same availability context as the @interface.
- else if (const ObjCImplementationDecl *ID =
- dyn_cast<ObjCImplementationDecl>(D)) {
- D = ID->getClassInterface();
- }
- // Recover from user error.
- return D ? D->getAvailability() : AR_Available;
-}