summaryrefslogtreecommitdiffstats
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.cpp120
1 files changed, 87 insertions, 33 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4d4637fd143..68762e97fa2 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1020,12 +1020,12 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
if (AddToContext)
CurContext->addDecl(D);
- // Out-of-line definitions shouldn't be pushed into scope in C++.
- // Out-of-line variable and function definitions shouldn't even in C.
- if ((getLangOpts().CPlusPlus || isa<VarDecl>(D) || isa<FunctionDecl>(D)) &&
- D->isOutOfLine() &&
+ // Out-of-line definitions shouldn't be pushed into scope in C++, unless they
+ // are function-local declarations.
+ if (getLangOpts().CPlusPlus && D->isOutOfLine() &&
!D->getDeclContext()->getRedeclContext()->Equals(
- D->getLexicalDeclContext()->getRedeclContext()))
+ D->getLexicalDeclContext()->getRedeclContext()) &&
+ !D->getLexicalDeclContext()->isFunctionOrMethod())
return;
// Template instantiations should also not be pushed into scope.
@@ -2426,7 +2426,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
: NewType)->getResultType();
QualType ResQT;
- if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType)) {
+ if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) &&
+ !((NewQType->isDependentType() || OldQType->isDependentType()) &&
+ New->isLocalExternDecl())) {
if (NewDeclaredReturnType->isObjCObjectPointerType() &&
OldDeclaredReturnType->isObjCObjectPointerType())
ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
@@ -2578,6 +2580,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
if (OldQTypeForComparison == NewQType)
return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
+ if ((NewQType->isDependentType() || OldQType->isDependentType()) &&
+ New->isLocalExternDecl()) {
+ // It's OK if we couldn't merge types for a local function declaraton
+ // if either the old or new type is dependent. We'll merge the types
+ // when we instantiate the function.
+ return false;
+ }
+
// Fall through for conflicting redeclarations and redefinitions.
}
@@ -2710,7 +2720,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
// local declaration will produce a hard error; if it doesn't
// remain visible, a single bogus local redeclaration (which is
// actually only a warning) could break all the downstream code.
- if (!New->getDeclContext()->isFunctionOrMethod())
+ if (!New->getLexicalDeclContext()->isFunctionOrMethod())
New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin);
return false;
@@ -2820,18 +2830,21 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old,
NewArray->getElementType()))
MergedT = New->getType();
} else if (Old->getType()->isArrayType() &&
- New->getType()->isIncompleteArrayType()) {
+ New->getType()->isIncompleteArrayType()) {
const ArrayType *OldArray = Context.getAsArrayType(Old->getType());
const ArrayType *NewArray = Context.getAsArrayType(New->getType());
if (Context.hasSameType(OldArray->getElementType(),
NewArray->getElementType()))
MergedT = Old->getType();
- } else if (New->getType()->isObjCObjectPointerType()
- && Old->getType()->isObjCObjectPointerType()) {
- MergedT = Context.mergeObjCGCQualifiers(New->getType(),
- Old->getType());
+ } else if (New->getType()->isObjCObjectPointerType() &&
+ Old->getType()->isObjCObjectPointerType()) {
+ MergedT = Context.mergeObjCGCQualifiers(New->getType(),
+ Old->getType());
}
} else {
+ // C 6.2.7p2:
+ // All declarations that refer to the same object or function shall have
+ // compatible type.
MergedT = Context.mergeTypes(New->getType(), Old->getType());
}
if (MergedT.isNull()) {
@@ -4308,8 +4321,15 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
// If this has an identifier and is not an invalid redeclaration or
// function template specialization, add it to the scope stack.
if (New->getDeclName() && AddToScope &&
- !(D.isRedeclaration() && New->isInvalidDecl()))
- PushOnScopeChains(New, S);
+ !(D.isRedeclaration() && New->isInvalidDecl())) {
+ // Only make a locally-scoped extern declaration visible if it is the first
+ // declaration of this entity. Qualified lookup for such an entity should
+ // only find this declaration if there is no visible declaration of it.
+ bool AddToContext = !D.isRedeclaration() || !New->isLocalExternDecl();
+ PushOnScopeChains(New, S, AddToContext);
+ if (!AddToContext)
+ CurContext->addHiddenDecl(New);
+ }
return New;
}
@@ -4808,6 +4828,30 @@ static bool shouldConsiderLinkage(const FunctionDecl *FD) {
llvm_unreachable("Unexpected context");
}
+/// Adjust the \c DeclContext for a function or variable that might be a
+/// function-local external declaration.
+bool Sema::adjustContextForLocalExternDecl(DeclContext *&DC) {
+ if (!DC->isFunctionOrMethod())
+ return false;
+
+ // If this is a local extern function or variable declared within a function
+ // template, don't add it into the enclosing namespace scope until it is
+ // instantiated; it might have a dependent type right now.
+ if (DC->isDependentContext())
+ return true;
+
+ // C++11 [basic.link]p7:
+ // When a block scope declaration of an entity with linkage is not found to
+ // refer to some other declaration, then that entity is a member of the
+ // innermost enclosing namespace.
+ //
+ // Per C++11 [namespace.def]p6, the innermost enclosing namespace is a
+ // semantically-enclosing namespace, not a lexically-enclosing one.
+ while (!DC->isFileContext() && !isa<LinkageSpecDecl>(DC))
+ DC = DC->getParent();
+ return true;
+}
+
NamedDecl *
Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -4820,6 +4864,10 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
VarDecl::StorageClass SC =
StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
+ DeclContext *OriginalDC = DC;
+ bool IsLocalExternDecl = SC == SC_Extern &&
+ adjustContextForLocalExternDecl(DC);
+
if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) {
// OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and
// half array type (unless the cl_khr_fp16 extension is enabled).
@@ -5150,6 +5198,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (NewTemplate)
NewTemplate->setLexicalDeclContext(CurContext);
+ if (IsLocalExternDecl)
+ NewVD->setLocalExternDecl();
+
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) {
if (NewVD->hasLocalStorage()) {
// C++11 [dcl.stc]p4:
@@ -5277,7 +5328,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
FilterLookupForScope(
- Previous, DC, S, shouldConsiderLinkage(NewVD),
+ Previous, OriginalDC, S, shouldConsiderLinkage(NewVD),
IsExplicitSpecialization || IsVariableTemplateSpecialization);
// Check whether the previous declaration is in the same block scope. This
@@ -5286,7 +5337,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->isLocalVarDecl() && NewVD->hasExternalStorage())
NewVD->setPreviousDeclInSameBlockScope(
Previous.isSingleResult() && !Previous.isShadowed() &&
- isDeclInScope(Previous.getFoundDecl(), DC, S, false));
+ isDeclInScope(Previous.getFoundDecl(), OriginalDC, S, false));
if (!getLangOpts().CPlusPlus) {
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
@@ -5543,12 +5594,8 @@ static bool checkForConflictWithNonVisibleExternC(Sema &S, const T *ND,
LookupResult &Previous) {
if (!S.getLangOpts().CPlusPlus) {
// In C, when declaring a global variable, look for a corresponding 'extern'
- // variable declared in function scope.
- //
- // FIXME: The corresponding case in C++ does not work. We should instead
- // set the semantic DC for an extern local variable to be the innermost
- // enclosing namespace, and ensure they are only found by redeclaration
- // lookup.
+ // variable declared in function scope. We don't need this in C++, because
+ // we find local extern decls in the surrounding file-scope DeclContext.
if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
if (NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName())) {
Previous.clear();
@@ -6032,6 +6079,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
bool FDisConst = MD && MD->isConst();
bool IsMember = MD || !IsLocalFriend;
+ // FIXME: These notes are poorly worded for the local friend case.
if (unsigned Idx = NearMatch->second) {
ParmVarDecl *FDParam = FD->getParamDecl(Idx-1);
SourceLocation Loc = FDParam->getTypeSpecStartLoc();
@@ -6455,6 +6503,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isVirtualOkay = false;
+ DeclContext *OriginalDC = DC;
+ bool IsLocalExternDecl = adjustContextForLocalExternDecl(DC);
+
FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC,
isVirtualOkay);
if (!NewFD) return 0;
@@ -6462,6 +6513,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer())
NewFD->setTopLevelDeclInObjCContainer();
+ // Set the lexical context. If this is a function-scope declaration, or has a
+ // C++ scope specifier, or is the object of a friend declaration, the lexical
+ // context will be different from the semantic context.
+ NewFD->setLexicalDeclContext(CurContext);
+
+ if (IsLocalExternDecl)
+ NewFD->setLocalExternDecl();
+
if (getLangOpts().CPlusPlus) {
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
@@ -6489,12 +6548,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
isFunctionTemplateSpecialization = false;
if (D.isInvalidType())
NewFD->setInvalidDecl();
-
- // Set the lexical context. If the declarator has a C++
- // scope specifier, or is the object of a friend declaration, the
- // lexical context will be different from the semantic context.
- NewFD->setLexicalDeclContext(CurContext);
-
+
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
bool Invalid = false;
@@ -6750,7 +6804,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewFD),
+ FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD),
isExplicitSpecialization ||
isFunctionTemplateSpecialization);
@@ -9232,21 +9286,21 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
// Don't warn for OpenCL kernels.
if (FD->hasAttr<OpenCLKernelAttr>())
return false;
-
+
bool MissingPrototype = true;
for (const FunctionDecl *Prev = FD->getPreviousDecl();
Prev; Prev = Prev->getPreviousDecl()) {
// Ignore any declarations that occur in function or method
// scope, because they aren't visible from the header.
- if (Prev->getDeclContext()->isFunctionOrMethod())
+ if (Prev->getLexicalDeclContext()->isFunctionOrMethod())
continue;
-
+
MissingPrototype = !Prev->getType()->isFunctionProtoType();
if (FD->getNumParams() == 0)
PossibleZeroParamPrototype = Prev;
break;
}
-
+
return MissingPrototype;
}
OpenPOWER on IntegriCloud