aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r--lib/Sema/SemaDecl.cpp911
1 files changed, 620 insertions, 291 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 1227e92f76eb..3aae99ab74e2 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -60,7 +61,8 @@ namespace {
class TypeNameValidatorCCC : public CorrectionCandidateCallback {
public:
- TypeNameValidatorCCC(bool AllowInvalid) : AllowInvalidDecl(AllowInvalid) {
+ TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false)
+ : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass) {
WantExpressionKeywords = false;
WantCXXNamedCasts = false;
WantRemainingKeywords = false;
@@ -71,15 +73,52 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback {
return (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) &&
(AllowInvalidDecl || !ND->isInvalidDecl());
else
- return candidate.isKeyword();
+ return !WantClassName && candidate.isKeyword();
}
private:
bool AllowInvalidDecl;
+ bool WantClassName;
};
}
+/// \brief Determine whether the token kind starts a simple-type-specifier.
+bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
+ switch (Kind) {
+ // FIXME: Take into account the current language when deciding whether a
+ // token kind is a valid type specifier
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw___int128:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_half:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw___underlying_type:
+ return true;
+
+ case tok::annot_typename:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_typeof:
+ case tok::kw_decltype:
+ return getLangOpts().CPlusPlus;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
/// \brief If the identifier refers to a type name within this scope,
/// return the declaration of that type.
///
@@ -173,7 +212,7 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
if (CorrectedII) {
- TypeNameValidatorCCC Validator(true);
+ TypeNameValidatorCCC Validator(true, isClassName);
TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(),
Kind, S, SS, Validator);
IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
@@ -202,8 +241,8 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
std::string CorrectedStr(Correction.getAsString(getLangOpts()));
std::string CorrectedQuotedStr(
Correction.getQuoted(getLangOpts()));
- Diag(NameLoc, diag::err_unknown_typename_suggest)
- << Result.getLookupName() << CorrectedQuotedStr
+ Diag(NameLoc, diag::err_unknown_type_or_class_name_suggest)
+ << Result.getLookupName() << CorrectedQuotedStr << isClassName
<< FixItHint::CreateReplacement(SourceRange(NameLoc),
CorrectedStr);
if (NamedDecl *FirstDecl = Correction.getCorrectionDecl())
@@ -359,7 +398,7 @@ bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) {
return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope();
}
-bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
+bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
SourceLocation IILoc,
Scope *S,
CXXScopeSpec *SS,
@@ -370,7 +409,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
// There may have been a typo in the name of the type. Look up typo
// results, in case we have something that we can suggest.
TypeNameValidatorCCC Validator(false);
- if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(&II, IILoc),
+ if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc),
LookupOrdinaryName, S, SS,
Validator)) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
@@ -378,19 +417,23 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
if (Corrected.isKeyword()) {
// We corrected to a keyword.
- // FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
+ IdentifierInfo *NewII = Corrected.getCorrectionAsIdentifierInfo();
+ if (!isSimpleTypeSpecifier(NewII->getTokenID()))
+ CorrectedQuotedStr = "the keyword " + CorrectedQuotedStr;
Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << CorrectedQuotedStr;
+ << II << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
+ II = NewII;
} else {
NamedDecl *Result = Corrected.getCorrectionDecl();
// We found a similarly-named type or interface; suggest that.
if (!SS || !SS->isSet())
Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << CorrectedQuotedStr
+ << II << CorrectedQuotedStr
<< FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
else if (DeclContext *DC = computeDeclContext(*SS, false))
Diag(IILoc, diag::err_unknown_nested_typename_suggest)
- << &II << DC << CorrectedQuotedStr << SS->getRange()
+ << II << DC << CorrectedQuotedStr << SS->getRange()
<< FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
else
llvm_unreachable("could not have corrected a typo here");
@@ -409,7 +452,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
if (getLangOpts().CPlusPlus) {
// See if II is a class template that the user forgot to pass arguments to.
UnqualifiedId Name;
- Name.setIdentifier(&II, IILoc);
+ Name.setIdentifier(II, IILoc);
CXXScopeSpec EmptySS;
TemplateTy TemplateResult;
bool MemberOfUnknownSpecialization;
@@ -430,21 +473,21 @@ bool Sema::DiagnoseUnknownTypeName(const 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, diag::err_unknown_typename) << II;
else if (DeclContext *DC = computeDeclContext(*SS, false))
Diag(IILoc, diag::err_typename_nested_not_found)
- << &II << DC << SS->getRange();
+ << II << DC << SS->getRange();
else if (isDependentScopeSpecifier(*SS)) {
unsigned DiagID = diag::err_typename_missing;
if (getLangOpts().MicrosoftMode && isMicrosoftMissingTypename(SS, S))
DiagID = diag::warn_typename_missing;
Diag(SS->getRange().getBegin(), DiagID)
- << (NestedNameSpecifier *)SS->getScopeRep() << II.getName()
+ << (NestedNameSpecifier *)SS->getScopeRep() << II->getName()
<< SourceRange(SS->getRange().getBegin(), IILoc)
<< FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename ");
- SuggestedType = ActOnTypenameType(S, SourceLocation(), *SS, II, IILoc)
- .get();
+ SuggestedType = ActOnTypenameType(S, SourceLocation(),
+ *SS, *II, IILoc).get();
} else {
assert(SS && SS->isInvalid() &&
"Invalid scope specifier has already been diagnosed");
@@ -470,6 +513,55 @@ static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) {
return false;
}
+static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
+ Scope *S, CXXScopeSpec &SS,
+ IdentifierInfo *&Name,
+ SourceLocation NameLoc) {
+ Result.clear(Sema::LookupTagName);
+ SemaRef.LookupParsedName(Result, S, &SS);
+ if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) {
+ const char *TagName = 0;
+ const char *FixItTagName = 0;
+ switch (Tag->getTagKind()) {
+ case TTK_Class:
+ TagName = "class";
+ FixItTagName = "class ";
+ break;
+
+ case TTK_Enum:
+ TagName = "enum";
+ FixItTagName = "enum ";
+ break;
+
+ case TTK_Struct:
+ TagName = "struct";
+ FixItTagName = "struct ";
+ break;
+
+ case TTK_Union:
+ TagName = "union";
+ FixItTagName = "union ";
+ break;
+ }
+
+ SemaRef.Diag(NameLoc, diag::err_use_of_tag_name_without_tag)
+ << Name << TagName << SemaRef.getLangOpts().CPlusPlus
+ << FixItHint::CreateInsertion(NameLoc, FixItTagName);
+
+ LookupResult R(SemaRef, Name, NameLoc, Sema::LookupOrdinaryName);
+ if (SemaRef.LookupParsedName(R, S, &SS)) {
+ for (LookupResult::iterator I = R.begin(), IEnd = R.end();
+ I != IEnd; ++I)
+ SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
+ << Name << TagName;
+ }
+ return true;
+ }
+
+ Result.clear(Sema::LookupOrdinaryName);
+ return false;
+}
+
Sema::NameClassification Sema::ClassifyName(Scope *S,
CXXScopeSpec &SS,
IdentifierInfo *&Name,
@@ -533,41 +625,9 @@ Corrected:
// In C, we first see whether there is a tag type by the same name, in
// which case it's likely that the user just forget to write "enum",
// "struct", or "union".
- if (!getLangOpts().CPlusPlus && !SecondTry) {
- Result.clear(LookupTagName);
- LookupParsedName(Result, S, &SS);
- if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) {
- const char *TagName = 0;
- const char *FixItTagName = 0;
- switch (Tag->getTagKind()) {
- case TTK_Class:
- TagName = "class";
- FixItTagName = "class ";
- break;
-
- case TTK_Enum:
- TagName = "enum";
- FixItTagName = "enum ";
- break;
-
- case TTK_Struct:
- TagName = "struct";
- FixItTagName = "struct ";
- break;
-
- case TTK_Union:
- TagName = "union";
- FixItTagName = "union ";
- break;
- }
-
- Diag(NameLoc, diag::err_use_of_tag_name_without_tag)
- << Name << TagName << getLangOpts().CPlusPlus
- << FixItHint::CreateInsertion(NameLoc, FixItTagName);
- break;
- }
-
- Result.clear(LookupOrdinaryName);
+ if (!getLangOpts().CPlusPlus && !SecondTry &&
+ isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
+ break;
}
// Perform typo correction to determine if there is another name that is
@@ -575,6 +635,19 @@ Corrected:
if (!SecondTry) {
SecondTry = true;
CorrectionCandidateCallback DefaultValidator;
+ // Try to limit which sets of keywords should be included in typo
+ // correction based on what the next token is.
+ DefaultValidator.WantTypeSpecifiers =
+ NextToken.is(tok::l_paren) || NextToken.is(tok::less) ||
+ NextToken.is(tok::identifier) || NextToken.is(tok::star) ||
+ NextToken.is(tok::amp) || NextToken.is(tok::l_square);
+ DefaultValidator.WantExpressionKeywords =
+ NextToken.is(tok::l_paren) || NextToken.is(tok::identifier) ||
+ NextToken.is(tok::arrow) || NextToken.is(tok::period);
+ DefaultValidator.WantRemainingKeywords =
+ NextToken.is(tok::l_paren) || NextToken.is(tok::semi) ||
+ NextToken.is(tok::identifier) || NextToken.is(tok::l_brace);
+ DefaultValidator.WantCXXNamedCasts = false;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S,
&SS, DefaultValidator)) {
@@ -740,7 +813,7 @@ Corrected:
if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
DiagnoseUseOfDecl(Type, NameLoc);
QualType T = Context.getTypeDeclType(Type);
- return ParsedType::make(T);
+ return ParsedType::make(T);
}
ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(FirstDecl);
@@ -764,6 +837,23 @@ Corrected:
QualType T = Context.getObjCInterfaceType(Class);
return ParsedType::make(T);
}
+
+ // Check for a tag type hidden by a non-type decl in a few cases where it
+ // seems likely a type is wanted instead of the non-type that was found.
+ if (!getLangOpts().ObjC1 && FirstDecl && !isa<ClassTemplateDecl>(FirstDecl) &&
+ !isa<TypeAliasTemplateDecl>(FirstDecl)) {
+ bool NextIsOp = NextToken.is(tok::amp) || NextToken.is(tok::star);
+ if ((NextToken.is(tok::identifier) ||
+ (NextIsOp && FirstDecl->isFunctionOrFunctionTemplate())) &&
+ isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
+ FirstDecl = (*Result.begin())->getUnderlyingDecl();
+ if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
+ DiagnoseUseOfDecl(Type, NameLoc);
+ QualType T = Context.getTypeDeclType(Type);
+ return ParsedType::make(T);
+ }
+ }
+ }
if (!Result.empty() && (*Result.begin())->isCXXClassMember())
return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, 0);
@@ -1132,9 +1222,9 @@ void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) {
return; // First should already be in the vector.
}
- if (ShouldWarnIfUnusedFileScopedDecl(D))
- UnusedFileScopedDecls.push_back(D);
- }
+ if (ShouldWarnIfUnusedFileScopedDecl(D))
+ UnusedFileScopedDecls.push_back(D);
+}
static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
if (D->isInvalidDecl())
@@ -1281,7 +1371,7 @@ void Sema::ActOnEndFunctionDeclarator() {
///
/// \param IdLoc The location of the name in the translation unit.
///
-/// \param TypoCorrection If true, this routine will attempt typo correction
+/// \param DoTypoCorrection If true, this routine will attempt typo correction
/// if there is no class with the given name.
///
/// \returns The declaration of the named Objective-C class, or NULL if the
@@ -1484,12 +1574,22 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
switch (TypeID->getLength()) {
default: break;
case 2:
- if (!TypeID->isStr("id"))
- break;
- Context.setObjCIdRedefinitionType(New->getUnderlyingType());
- // Install the built-in type for 'id', ignoring the current definition.
- New->setTypeForDecl(Context.getObjCIdType().getTypePtr());
- return;
+ {
+ if (!TypeID->isStr("id"))
+ break;
+ QualType T = New->getUnderlyingType();
+ if (!T->isPointerType())
+ break;
+ if (!T->isVoidPointerType()) {
+ QualType PT = T->getAs<PointerType>()->getPointeeType();
+ if (!PT->isStructureType())
+ break;
+ }
+ Context.setObjCIdRedefinitionType(T);
+ // Install the built-in type for 'id', ignoring the current definition.
+ New->setTypeForDecl(Context.getObjCIdType().getTypePtr());
+ return;
+ }
case 5:
if (!TypeID->isStr("Class"))
break;
@@ -1599,6 +1699,13 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
/// attribute.
static bool
DeclHasAttr(const Decl *D, const Attr *A) {
+ // There can be multiple AvailabilityAttr in a Decl. Make sure we copy
+ // all of them. It is mergeAvailabilityAttr in SemaDeclAttr.cpp that is
+ // responsible for making sure they are consistent.
+ const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(A);
+ if (AA)
+ return false;
+
const OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A);
const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A);
for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i)
@@ -1617,9 +1724,90 @@ DeclHasAttr(const Decl *D, const Attr *A) {
return false;
}
+bool Sema::mergeDeclAttribute(Decl *D, InheritableAttr *Attr) {
+ InheritableAttr *NewAttr = NULL;
+ if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr))
+ NewAttr = mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
+ AA->getIntroduced(), AA->getDeprecated(),
+ AA->getObsoleted(), AA->getUnavailable(),
+ AA->getMessage());
+ else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr))
+ NewAttr = mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility());
+ else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr))
+ NewAttr = mergeDLLImportAttr(D, ImportA->getRange());
+ else if (DLLExportAttr *ExportA = dyn_cast<DLLExportAttr>(Attr))
+ NewAttr = mergeDLLExportAttr(D, ExportA->getRange());
+ else if (FormatAttr *FA = dyn_cast<FormatAttr>(Attr))
+ NewAttr = mergeFormatAttr(D, FA->getRange(), FA->getType(),
+ FA->getFormatIdx(), FA->getFirstArg());
+ else if (SectionAttr *SA = dyn_cast<SectionAttr>(Attr))
+ NewAttr = mergeSectionAttr(D, SA->getRange(), SA->getName());
+ else if (!DeclHasAttr(D, Attr))
+ NewAttr = cast<InheritableAttr>(Attr->clone(Context));
+
+ if (NewAttr) {
+ NewAttr->setInherited(true);
+ D->addAttr(NewAttr);
+ return true;
+ }
+
+ return false;
+}
+
+static const Decl *getDefinition(const Decl *D) {
+ if (const TagDecl *TD = dyn_cast<TagDecl>(D))
+ return TD->getDefinition();
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ return VD->getDefinition();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ const FunctionDecl* Def;
+ if (FD->hasBody(Def))
+ return Def;
+ }
+ return NULL;
+}
+
+static bool hasAttribute(const Decl *D, attr::Kind Kind) {
+ for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end();
+ I != E; ++I) {
+ Attr *Attribute = *I;
+ if (Attribute->getKind() == Kind)
+ return true;
+ }
+ return false;
+}
+
+/// checkNewAttributesAfterDef - If we already have a definition, check that
+/// there are no new attributes in this declaration.
+static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
+ if (!New->hasAttrs())
+ return;
+
+ const Decl *Def = getDefinition(Old);
+ if (!Def || Def == New)
+ return;
+
+ AttrVec &NewAttributes = New->getAttrs();
+ for (unsigned I = 0, E = NewAttributes.size(); I != E;) {
+ const Attr *NewAttribute = NewAttributes[I];
+ if (hasAttribute(Def, NewAttribute->getKind())) {
+ ++I;
+ continue; // regular attr merging will take care of validating this.
+ }
+ S.Diag(NewAttribute->getLocation(),
+ diag::warn_attribute_precede_definition);
+ S.Diag(Def->getLocation(), diag::note_previous_definition);
+ NewAttributes.erase(NewAttributes.begin() + I);
+ --E;
+ }
+}
+
/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
bool MergeDeprecation) {
+ // attributes declared post-definition are currently ignored
+ checkNewAttributesAfterDef(*this, New, Old);
+
if (!Old->hasAttrs())
return;
@@ -1640,12 +1828,8 @@ void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
isa<AvailabilityAttr>(*i)))
continue;
- if (!DeclHasAttr(New, *i)) {
- InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(Context));
- newAttr->setInherited(true);
- New->addAttr(newAttr);
+ if (mergeDeclAttribute(New, *i))
foundAny = true;
- }
}
if (!foundAny) New->dropAttrs();
@@ -1909,22 +2093,27 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
return true;
}
-
+
// C++ [class.mem]p1:
// [...] A member shall not be declared twice in the
// member-specification, except that a nested class or member
// class template can be declared and then later defined.
- unsigned NewDiag;
- if (isa<CXXConstructorDecl>(OldMethod))
- NewDiag = diag::err_constructor_redeclared;
- else if (isa<CXXDestructorDecl>(NewMethod))
- NewDiag = diag::err_destructor_redeclared;
- else if (isa<CXXConversionDecl>(NewMethod))
- NewDiag = diag::err_conv_function_redeclared;
- else
- NewDiag = diag::err_member_redeclared;
+ if (ActiveTemplateInstantiations.empty()) {
+ unsigned NewDiag;
+ if (isa<CXXConstructorDecl>(OldMethod))
+ NewDiag = diag::err_constructor_redeclared;
+ else if (isa<CXXDestructorDecl>(NewMethod))
+ NewDiag = diag::err_destructor_redeclared;
+ else if (isa<CXXConversionDecl>(NewMethod))
+ NewDiag = diag::err_conv_function_redeclared;
+ else
+ NewDiag = diag::err_member_redeclared;
- Diag(New->getLocation(), NewDiag);
+ Diag(New->getLocation(), NewDiag);
+ } else {
+ Diag(New->getLocation(), diag::err_member_redeclared_in_instantiation)
+ << New << New->getType();
+ }
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
// Complain if this is an explicit declaration of a special
@@ -1941,7 +2130,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
<< New << getSpecialMember(OldMethod);
return true;
}
- } else if (OldMethod->isExplicitlyDefaulted()) {
+ } else if (OldMethod->isExplicitlyDefaulted() && !isFriend) {
Diag(NewMethod->getLocation(),
diag::err_definition_of_explicitly_defaulted_member)
<< getSpecialMember(OldMethod);
@@ -2142,18 +2331,16 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
ObjCMethodDecl *oldMethod) {
- // We don't want to merge unavailable and deprecated attributes
- // except from interface to implementation.
- bool mergeDeprecation = isa<ObjCImplDecl>(newMethod->getDeclContext());
- // Merge the attributes.
- mergeDeclAttributes(newMethod, oldMethod, mergeDeprecation);
+ // Merge the attributes, including deprecated/unavailable
+ mergeDeclAttributes(newMethod, oldMethod, /* mergeDeprecation */true);
// Merge attributes from the parameters.
- ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin();
+ ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(),
+ oe = oldMethod->param_end();
for (ObjCMethodDecl::param_iterator
ni = newMethod->param_begin(), ne = newMethod->param_end();
- ni != ne; ++ni, ++oi)
+ ni != ne && oi != oe; ++ni, ++oi)
mergeParamDeclAttributes(*ni, *oi, Context);
CheckObjCMethodOverride(newMethod, oldMethod, true);
@@ -2552,6 +2739,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
}
+ ActOnDocumentableDecl(TagD);
+
return TagD;
}
@@ -2873,7 +3062,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Context.getTypeDeclType(Record),
TInfo,
/*BitWidth=*/0, /*Mutable=*/false,
- /*HasInit=*/false);
+ /*InitStyle=*/ICIS_NoInit);
Anon->setAccess(AS);
if (getLangOpts().CPlusPlus)
FieldCollector->Add(cast<FieldDecl>(Anon));
@@ -2970,7 +3159,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
Context.getTypeDeclType(Record),
TInfo,
/*BitWidth=*/0, /*Mutable=*/false,
- /*HasInit=*/false);
+ /*InitStyle=*/ICIS_NoInit);
Anon->setImplicit();
// Add the anonymous struct object to the current context.
@@ -3225,7 +3414,7 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg(*this));
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() &&
- Dcl->getDeclContext()->isFileContext())
+ Dcl && Dcl->getDeclContext()->isFileContext())
Dcl->setTopLevelDeclInObjCContainer();
return Dcl;
@@ -3794,8 +3983,6 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
Context.setsigjmp_bufDecl(NewTD);
else if (II->isStr("ucontext_t"))
Context.setucontext_tDecl(NewTD);
- else if (II->isStr("__builtin_va_list"))
- Context.setBuiltinVaListType(Context.getTypedefType(NewTD));
}
return NewTD;
@@ -4173,18 +4360,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
CheckMemberSpecialization(NewVD, Previous))
NewVD->setInvalidDecl();
}
-
- // attributes declared post-definition are currently ignored
- // FIXME: This should be handled in attribute merging, not
- // here.
- if (Previous.isSingleResult()) {
- VarDecl *Def = dyn_cast<VarDecl>(Previous.getFoundDecl());
- if (Def && (Def = Def->getDefinition()) &&
- Def != NewVD && D.hasAttributes()) {
- Diag(NewVD->getLocation(), diag::warn_attribute_precede_definition);
- Diag(Def->getLocation(), diag::note_previous_definition);
- }
- }
// If this is a locally-scoped extern C variable, update the map of
// such variables.
@@ -4334,6 +4509,15 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
return false;
}
+ // OpenCL v1.2 s6.8 -- The static qualifier is valid only in program
+ // scope.
+ if ((getLangOpts().OpenCLVersion >= 120)
+ && NewVD->isStaticLocal()) {
+ Diag(NewVD->getLocation(), diag::err_static_function_scope);
+ NewVD->setInvalidDecl();
+ return false;
+ }
+
if (NewVD->hasLocalStorage() && T.isObjCGCWeak()
&& !NewVD->hasAttr<BlocksAttr>()) {
if (getLangOpts().getGC() != LangOptions::NonGC)
@@ -4418,7 +4602,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
if (NewVD->isConstexpr() && !T->isDependentType() &&
RequireLiteralType(NewVD->getLocation(), T,
- PDiag(diag::err_constexpr_var_non_literal))) {
+ diag::err_constexpr_var_non_literal)) {
NewVD->setInvalidDecl();
return false;
}
@@ -4471,11 +4655,6 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier,
return false;
}
-static bool hasDelayedExceptionSpec(CXXMethodDecl *Method) {
- const FunctionProtoType *Proto =Method->getType()->getAs<FunctionProtoType>();
- return Proto && Proto->getExceptionSpecType() == EST_Delayed;
-}
-
/// AddOverriddenMethods - See if a method overrides any in the base classes,
/// and if so, check that it's a valid override and remember it.
bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
@@ -4491,8 +4670,7 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
MD->addOverriddenMethod(OldMD->getCanonicalDecl());
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
- (hasDelayedExceptionSpec(MD) ||
- !CheckOverridingFunctionExceptionSpec(MD, OldMD)) &&
+ !CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
!CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
AddedAny = true;
}
@@ -4520,22 +4698,39 @@ namespace {
// Also only accept corrections that have the same parent decl.
class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
public:
- DifferentNameValidatorCCC(CXXRecordDecl *Parent)
- : ExpectedParent(Parent ? Parent->getCanonicalDecl() : 0) {}
+ DifferentNameValidatorCCC(ASTContext &Context, FunctionDecl *TypoFD,
+ CXXRecordDecl *Parent)
+ : Context(Context), OriginalFD(TypoFD),
+ ExpectedParent(Parent ? Parent->getCanonicalDecl() : 0) {}
virtual bool ValidateCandidate(const TypoCorrection &candidate) {
if (candidate.getEditDistance() == 0)
return false;
- if (CXXMethodDecl *MD = candidate.getCorrectionDeclAs<CXXMethodDecl>()) {
- CXXRecordDecl *Parent = MD->getParent();
- return Parent && Parent->getCanonicalDecl() == ExpectedParent;
+ llvm::SmallVector<unsigned, 1> MismatchedParams;
+ for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(),
+ CDeclEnd = candidate.end();
+ CDecl != CDeclEnd; ++CDecl) {
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(*CDecl);
+
+ if (FD && !FD->hasBody() &&
+ hasSimilarParameters(Context, FD, OriginalFD, MismatchedParams)) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ CXXRecordDecl *Parent = MD->getParent();
+ if (Parent && Parent->getCanonicalDecl() == ExpectedParent)
+ return true;
+ } else if (!ExpectedParent) {
+ return true;
+ }
+ }
}
- return !ExpectedParent;
+ return false;
}
private:
+ ASTContext &Context;
+ FunctionDecl *OriginalFD;
CXXRecordDecl *ExpectedParent;
};
@@ -4571,7 +4766,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
- DifferentNameValidatorCCC Validator(MD ? MD->getParent() : 0);
+ DifferentNameValidatorCCC Validator(SemaRef.Context, NewFD,
+ MD ? MD->getParent() : 0);
if (!Prev.empty()) {
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
Func != FuncEnd; ++Func) {
@@ -4601,8 +4797,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
CDeclEnd = Correction.end();
CDecl != CDeclEnd; ++CDecl) {
FunctionDecl *FD = dyn_cast<FunctionDecl>(*CDecl);
- if (FD && hasSimilarParameters(SemaRef.Context, FD, NewFD,
- MismatchedParams)) {
+ if (FD && !FD->hasBody() &&
+ hasSimilarParameters(SemaRef.Context, FD, NewFD, MismatchedParams)) {
Previous.addDecl(FD);
}
}
@@ -4640,19 +4836,23 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
}
}
- if (Correction)
- SemaRef.Diag(NewFD->getLocation(), DiagMsg)
+ if (Correction) {
+ SourceRange FixItLoc(NewFD->getLocation());
+ CXXScopeSpec &SS = ExtraArgs.D.getCXXScopeSpec();
+ if (Correction.getCorrectionSpecifier() && SS.isValid())
+ FixItLoc.setBegin(SS.getBeginLoc());
+ SemaRef.Diag(NewFD->getLocStart(), DiagMsg)
<< Name << NewDC << Correction.getQuoted(SemaRef.getLangOpts())
<< FixItHint::CreateReplacement(
- NewFD->getLocation(),
- Correction.getAsString(SemaRef.getLangOpts()));
- else
+ FixItLoc, Correction.getAsString(SemaRef.getLangOpts()));
+ } else {
SemaRef.Diag(NewFD->getLocation(), DiagMsg)
<< Name << NewDC << NewFD->getLocation();
+ }
bool NewFDisConst = false;
if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
- NewFDisConst = NewMD->getTypeQualifiers() & Qualifiers::Const;
+ NewFDisConst = NewMD->isConst();
for (llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1>::iterator
NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();
@@ -4660,7 +4860,7 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
FunctionDecl *FD = NearMatch->first;
bool FDisConst = false;
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
- FDisConst = MD->getTypeQualifiers() & Qualifiers::Const;
+ FDisConst = MD->isConst();
if (unsigned Idx = NearMatch->second) {
ParmVarDecl *FDParam = FD->getParamDecl(Idx-1);
@@ -4911,7 +5111,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FunctionTemplateDecl *FunctionTemplate = 0;
bool isExplicitSpecialization = false;
bool isFunctionTemplateSpecialization = false;
+
bool isDependentClassScopeExplicitSpecialization = false;
+ bool HasExplicitTemplateArgs = false;
+ TemplateArgumentListInfo TemplateArgs;
+
bool isVirtualOkay = false;
FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC,
@@ -5041,56 +5245,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FunctionTemplate->setInvalidDecl();
}
- // If we see "T var();" at block scope, where T is a class type, it is
- // probably an attempt to initialize a variable, not a function declaration.
- // We don't catch this case earlier, since there is no ambiguity here.
- if (!FunctionTemplate && D.getFunctionDefinitionKind() == FDK_Declaration &&
- CurContext->isFunctionOrMethod() &&
- D.getNumTypeObjects() == 1 && D.isFunctionDeclarator() &&
- D.getDeclSpec().getStorageClassSpecAsWritten()
- == DeclSpec::SCS_unspecified) {
- QualType T = R->getAs<FunctionType>()->getResultType();
- DeclaratorChunk &C = D.getTypeObject(0);
- if (!T->isVoidType() && C.Fun.NumArgs == 0 && !C.Fun.isVariadic &&
- !C.Fun.TrailingReturnType &&
- C.Fun.getExceptionSpecType() == EST_None) {
- SourceRange ParenRange(C.Loc, C.EndLoc);
- Diag(C.Loc, diag::warn_empty_parens_are_function_decl) << ParenRange;
-
- // If the declaration looks like:
- // T var1,
- // f();
- // and name lookup finds a function named 'f', then the ',' was
- // probably intended to be a ';'.
- if (!D.isFirstDeclarator() && D.getIdentifier()) {
- FullSourceLoc Comma(D.getCommaLoc(), SourceMgr);
- FullSourceLoc Name(D.getIdentifierLoc(), SourceMgr);
- if (Comma.getFileID() != Name.getFileID() ||
- Comma.getSpellingLineNumber() != Name.getSpellingLineNumber()) {
- LookupResult Result(*this, D.getIdentifier(), SourceLocation(),
- LookupOrdinaryName);
- if (LookupName(Result, S))
- Diag(D.getCommaLoc(), diag::note_empty_parens_function_call)
- << FixItHint::CreateReplacement(D.getCommaLoc(), ";") << NewFD;
- }
- }
- const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
- // Empty parens mean value-initialization, and no parens mean default
- // initialization. These are equivalent if the default constructor is
- // user-provided, or if zero-initialization is a no-op.
- if (RD && RD->hasDefinition() &&
- (RD->isEmpty() || RD->hasUserProvidedDefaultConstructor()))
- Diag(C.Loc, diag::note_empty_parens_default_ctor)
- << FixItHint::CreateRemoval(ParenRange);
- else if (const char *Init = getFixItZeroInitializerForType(T))
- Diag(C.Loc, diag::note_empty_parens_zero_initialize)
- << FixItHint::CreateReplacement(ParenRange, Init);
- else if (LangOpts.CPlusPlus0x)
- Diag(C.Loc, diag::note_empty_parens_zero_initialize)
- << FixItHint::CreateReplacement(ParenRange, "{}");
- }
- }
-
// C++ [dcl.fct.spec]p5:
// The virtual specifier shall only be used in declarations of
// nonstatic class member functions that appear within a
@@ -5333,6 +5487,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setInvalidDecl();
}
+ // Handle attributes.
+ ProcessDeclAttributes(S, NewFD, D,
+ /*NonInheritable=*/false, /*Inheritable=*/true);
+
if (!getLangOpts().CPlusPlus) {
// Perform semantic checking on the function declaration.
bool isExplicitSpecialization=false;
@@ -5348,8 +5506,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
} else {
// If the declarator is a template-id, translate the parser's template
// argument list into our AST format.
- bool HasExplicitTemplateArgs = false;
- TemplateArgumentListInfo TemplateArgs;
if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
@@ -5580,25 +5736,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< D.getCXXScopeSpec().getRange();
}
}
-
-
- // Handle attributes. We need to have merged decls when handling attributes
- // (for example to check for conflicts, etc).
- // FIXME: This needs to happen before we merge declarations. Then,
- // let attribute merging cope with attribute conflicts.
- ProcessDeclAttributes(S, NewFD, D,
- /*NonInheritable=*/false, /*Inheritable=*/true);
-
- // attributes declared post-definition are currently ignored
- // FIXME: This should happen during attribute merging
- if (D.isRedeclaration() && Previous.isSingleResult()) {
- const FunctionDecl *Def;
- FunctionDecl *PrevFD = dyn_cast<FunctionDecl>(Previous.getFoundDecl());
- if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) {
- Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition);
- Diag(Def->getLocation(), diag::note_previous_definition);
- }
- }
AddKnownFunctionAttributes(NewFD);
@@ -5644,6 +5781,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ // OpenCL v1.2 s6.8 static is invalid for kernel functions.
+ if ((getLangOpts().OpenCLVersion >= 120)
+ && NewFD->hasAttr<OpenCLKernelAttr>()
+ && (SC == SC_Static)) {
+ Diag(D.getIdentifierLoc(), diag::err_static_kernel);
+ D.setInvalidType();
+ }
+
MarkUnusedFileScopedDecl(NewFD);
if (getLangOpts().CUDA)
@@ -5664,8 +5809,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (isDependentClassScopeExplicitSpecialization) {
ClassScopeFunctionSpecializationDecl *NewSpec =
ClassScopeFunctionSpecializationDecl::Create(
- Context, CurContext, SourceLocation(),
- cast<CXXMethodDecl>(NewFD));
+ Context, CurContext, SourceLocation(),
+ cast<CXXMethodDecl>(NewFD),
+ HasExplicitTemplateArgs, TemplateArgs);
CurContext->addDecl(NewSpec);
AddToScope = false;
}
@@ -5683,12 +5829,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
/// that have been instantiated via C++ template instantiation (called
/// via InstantiateDecl).
///
-/// \param IsExplicitSpecialiation whether this new function declaration is
+/// \param IsExplicitSpecialization whether this new function declaration is
/// an explicit specialization of the previous declaration.
///
/// This sets NewFD->isInvalidDecl() to true if there was an error.
///
-/// Returns true if the function declaration is a redeclaration.
+/// \returns true if the function declaration is a redeclaration.
bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
LookupResult &Previous,
bool IsExplicitSpecialization) {
@@ -5882,10 +6028,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// compatible, and if it does, warn the user.
if (NewFD->isExternC()) {
QualType R = NewFD->getResultType();
- if (!R.isPODType(Context) &&
- !R->isVoidType())
- Diag( NewFD->getLocation(), diag::warn_return_value_udt )
- << NewFD << R;
+ if (R->isIncompleteType() && !R->isVoidType())
+ Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete)
+ << NewFD << R;
+ else if (!R.isPODType(Context) && !R->isVoidType() &&
+ !R->isObjCObjectPointerType())
+ Diag(NewFD->getLocation(), diag::warn_return_value_udt) << NewFD << R;
}
}
return Redeclaration;
@@ -6040,55 +6188,73 @@ namespace {
}
}
- void VisitExpr(Expr *E) {
- if (isa<ObjCMessageExpr>(*E)) return;
- if (isRecordType) {
- Expr *expr = E;
- if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- ValueDecl *VD = ME->getMemberDecl();
- if (isa<EnumConstantDecl>(VD) || isa<VarDecl>(VD)) return;
- expr = ME->getBase();
- }
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(expr)) {
+ // Sometimes, the expression passed in lacks the casts that are used
+ // to determine which DeclRefExpr's to check. Assume that the casts
+ // are present and continue visiting the expression.
+ void HandleExpr(Expr *E) {
+ // Skip checking T a = a where T is not a record type. Doing so is a
+ // way to silence uninitialized warnings.
+ if (isRecordType)
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
HandleDeclRefExpr(DRE);
- return;
- }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ HandleValue(CO->getTrueExpr());
+ HandleValue(CO->getFalseExpr());
+ }
+
+ Visit(E);
+ }
+
+ // For most expressions, the cast is directly above the DeclRefExpr.
+ // For conditional operators, the cast can be outside the conditional
+ // operator if both expressions are DeclRefExpr's.
+ void HandleValue(Expr *E) {
+ E = E->IgnoreParenImpCasts();
+ if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(E)) {
+ HandleDeclRefExpr(DRE);
+ return;
+ }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ HandleValue(CO->getTrueExpr());
+ HandleValue(CO->getFalseExpr());
}
- Inherited::VisitExpr(E);
+ }
+
+ void VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ if ((!isRecordType && E->getCastKind() == CK_LValueToRValue) ||
+ (isRecordType && E->getCastKind() == CK_NoOp))
+ HandleValue(E->getSubExpr());
+
+ Inherited::VisitImplicitCastExpr(E);
}
void VisitMemberExpr(MemberExpr *E) {
+ // Don't warn on arrays since they can be treated as pointers.
if (E->getType()->canDecayToPointerType()) return;
+
ValueDecl *VD = E->getMemberDecl();
- if (isa<FieldDecl>(VD) || isa<CXXMethodDecl>(VD))
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(VD);
+ if (isa<FieldDecl>(VD) || (MD && !MD->isStatic()))
if (DeclRefExpr *DRE
= dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) {
HandleDeclRefExpr(DRE);
return;
}
- Inherited::VisitMemberExpr(E);
- }
- void VisitImplicitCastExpr(ImplicitCastExpr *E) {
- if ((!isRecordType &&E->getCastKind() == CK_LValueToRValue) ||
- (isRecordType && E->getCastKind() == CK_NoOp)) {
- Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts();
- if (MemberExpr *ME = dyn_cast<MemberExpr>(SubExpr))
- SubExpr = ME->getBase()->IgnoreParenImpCasts();
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr)) {
- HandleDeclRefExpr(DRE);
- return;
- }
- }
- Inherited::VisitImplicitCastExpr(E);
+ Inherited::VisitMemberExpr(E);
}
void VisitUnaryOperator(UnaryOperator *E) {
// For POD record types, addresses of its own members are well-defined.
- if (isRecordType && isPODType) return;
+ if (E->getOpcode() == UO_AddrOf && isRecordType && isPODType &&
+ isa<MemberExpr>(E->getSubExpr()->IgnoreParens())) return;
Inherited::VisitUnaryOperator(E);
}
-
+
+ void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; }
+
void HandleDeclRefExpr(DeclRefExpr *DRE) {
Decl* ReferenceDecl = DRE->getDecl();
if (OrigDecl != ReferenceDecl) return;
@@ -6105,7 +6271,7 @@ namespace {
/// CheckSelfReference - Warns if OrigDecl is used in expression E.
void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) {
- SelfReferenceChecker(*this, OrigDecl).VisitExpr(E);
+ SelfReferenceChecker(*this, OrigDecl).HandleExpr(E);
}
/// AddInitializerToDecl - Adds the initializer Init to the
@@ -6145,13 +6311,19 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// Check for self-references within variable initializers.
// Variables declared within a function/method body are handled
// by a dataflow analysis.
- if (!VDecl->hasLocalStorage() && !VDecl->isStaticLocal())
+ // Record types initialized by initializer list are handled here.
+ // Initialization by constructors are handled in TryConstructorInitialization.
+ if (!VDecl->hasLocalStorage() && !VDecl->isStaticLocal() &&
+ (isa<InitListExpr>(Init) || !VDecl->getType()->isRecordType()))
CheckSelfReference(RealDecl, Init);
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
- if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
+ AutoType *Auto = 0;
+ if (TypeMayContainAuto &&
+ (Auto = VDecl->getType()->getContainedAutoType()) &&
+ !Auto->isDeduced()) {
Expr *DeduceInit = Init;
// Initializer could be a C++ direct-initializer. Deduction only works if it
// contains exactly one expression.
@@ -6192,6 +6364,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
VDecl->setInvalidDecl();
+ // Warn if we deduced 'id'. 'auto' usually implies type-safety, but using
+ // 'id' instead of a specific object type prevents most of our usual checks.
+ // We only want to warn outside of template instantiations, though:
+ // inside a template, the 'id' could have come from a parameter.
+ if (ActiveTemplateInstantiations.empty() &&
+ DeducedType->getType()->isObjCIdType()) {
+ SourceLocation Loc = DeducedType->getTypeLoc().getBeginLoc();
+ Diag(Loc, diag::warn_auto_var_is_id)
+ << VDecl->getDeclName() << DeduceInit->getSourceRange();
+ }
+
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDecl())
@@ -6906,9 +7089,55 @@ Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls,
}
}
+ ActOnDocumentableDecls(Group, NumDecls);
+
return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, NumDecls));
}
+void Sema::ActOnDocumentableDecl(Decl *D) {
+ ActOnDocumentableDecls(&D, 1);
+}
+
+void Sema::ActOnDocumentableDecls(Decl **Group, unsigned NumDecls) {
+ // Don't parse the comment if Doxygen diagnostics are ignored.
+ if (NumDecls == 0 || !Group[0])
+ return;
+
+ if (Diags.getDiagnosticLevel(diag::warn_doc_param_not_found,
+ Group[0]->getLocation())
+ == DiagnosticsEngine::Ignored)
+ return;
+
+ if (NumDecls >= 2) {
+ // This is a decl group. Normally it will contain only declarations
+ // procuded from declarator list. But in case we have any definitions or
+ // additional declaration references:
+ // 'typedef struct S {} S;'
+ // 'typedef struct S *S;'
+ // 'struct S *pS;'
+ // FinalizeDeclaratorGroup adds these as separate declarations.
+ Decl *MaybeTagDecl = Group[0];
+ if (MaybeTagDecl && isa<TagDecl>(MaybeTagDecl)) {
+ Group++;
+ NumDecls--;
+ }
+ }
+
+ // See if there are any new comments that are not attached to a decl.
+ ArrayRef<RawComment *> Comments = Context.getRawCommentList().getComments();
+ if (!Comments.empty() &&
+ !Comments.back()->isAttached()) {
+ // There is at least one comment that not attached to a decl.
+ // Maybe it should be attached to one of these decls?
+ //
+ // Note that this way we pick up not only comments that precede the
+ // declaration, but also comments that *follow* the declaration -- thanks to
+ // the lookahead in the lexer: we've consumed the semicolon and looked
+ // ahead through comments.
+ for (unsigned i = 0; i != NumDecls; ++i)
+ Context.getCommentForDecl(Group[i]);
+ }
+}
/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
/// to introduce parameters into function prototype scope.
@@ -7132,9 +7361,10 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// Parameter declarators cannot be interface types. All ObjC objects are
// passed by reference.
if (T->isObjCObjectType()) {
+ SourceLocation TypeEndLoc = TSInfo->getTypeLoc().getLocEnd();
Diag(NameLoc,
diag::err_object_cannot_be_passed_returned_by_value) << 1 << T
- << FixItHint::CreateInsertion(NameLoc, "*");
+ << FixItHint::CreateInsertion(TypeEndLoc, "*");
T = Context.getObjCObjectPointerType(T);
New->setType(T);
}
@@ -7225,6 +7455,10 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) {
if (FD->isFunctionTemplateSpecialization())
return false;
+ // 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()) {
@@ -7253,6 +7487,7 @@ void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) {
else
Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
Diag(Definition->getLocation(), diag::note_previous_definition);
+ FD->setInvalidDecl();
}
}
@@ -7388,6 +7623,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
<< FD->getName() << "dllimport";
}
}
+ ActOnDocumentableDecl(FD);
return FD;
}
@@ -7463,7 +7699,12 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD))
MarkVTableUsed(FD->getLocation(), Constructor->getParent());
- computeNRVO(Body, getCurFunction());
+ // Try to apply the named return value optimization. We have to check
+ // if we can do this here because lambdas keep return statements around
+ // to deduce an implicit return type.
+ if (getLangOpts().CPlusPlus && FD->getResultType()->isRecordType() &&
+ !FD->isDependentContext())
+ computeNRVO(Body, getCurFunction());
}
assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) &&
@@ -7471,8 +7712,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
MD->setBody(Body);
- if (Body)
- MD->setEndLoc(Body->getLocEnd());
if (!MD->isInvalidDecl()) {
DiagnoseUnusedParameters(MD->param_begin(), MD->param_end());
DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(),
@@ -7481,22 +7720,24 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (Body)
computeNRVO(Body, getCurFunction());
}
- if (ObjCShouldCallSuperDealloc) {
+ if (getCurFunction()->ObjCShouldCallSuperDealloc) {
Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc);
- ObjCShouldCallSuperDealloc = false;
+ getCurFunction()->ObjCShouldCallSuperDealloc = false;
}
- if (ObjCShouldCallSuperFinalize) {
+ if (getCurFunction()->ObjCShouldCallSuperFinalize) {
Diag(MD->getLocEnd(), diag::warn_objc_missing_super_finalize);
- ObjCShouldCallSuperFinalize = false;
+ getCurFunction()->ObjCShouldCallSuperFinalize = false;
}
} else {
return 0;
}
- assert(!ObjCShouldCallSuperDealloc && "This should only be set for "
- "ObjC methods, which should have been handled in the block above.");
- assert(!ObjCShouldCallSuperFinalize && "This should only be set for "
- "ObjC methods, which should have been handled in the block above.");
+ assert(!getCurFunction()->ObjCShouldCallSuperDealloc &&
+ "This should only be set for ObjC methods, which should have been "
+ "handled in the block above.");
+ assert(!getCurFunction()->ObjCShouldCallSuperFinalize &&
+ "This should only be set for ObjC methods, which should have been "
+ "handled in the block above.");
// Verify and clean out per-function state.
if (Body) {
@@ -7630,10 +7871,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
(void)Error; // Silence warning.
assert(!Error && "Error setting up implicit decl!");
Declarator D(DS, Declarator::BlockContext);
- D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
- 0, 0, true, SourceLocation(),
+ D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, false,
+ SourceLocation(), 0, 0, 0, true,
+ SourceLocation(), SourceLocation(),
SourceLocation(), SourceLocation(),
- SourceLocation(),
EST_None, SourceLocation(),
0, 0, 0, 0, Loc, Loc, D),
DS.getAttributes(),
@@ -7733,6 +7974,13 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
"printf", 2,
Name->isStr("vasprintf") ? 0 : 3));
}
+
+ if (Name->isStr("__CFStringMakeConstantString")) {
+ // We already have a __builtin___CFStringMakeConstantString,
+ // but builds that use -fno-constant-cfstrings don't go through that.
+ if (!FD->getAttr<FormatArgAttr>())
+ FD->addAttr(::new (Context) FormatArgAttr(FD->getLocation(), Context, 1));
+ }
}
TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
@@ -8566,9 +8814,10 @@ CreateNewDecl:
// many points during the parsing of a struct declaration (because
// the #pragma tokens are effectively skipped over during the
// parsing of the struct).
- AddAlignmentAttributesForRecord(RD);
-
- AddMsStructLayoutForRecord(RD);
+ if (TUK == TUK_Definition) {
+ AddAlignmentAttributesForRecord(RD);
+ AddMsStructLayoutForRecord(RD);
+ }
}
if (ModulePrivateLoc.isValid()) {
@@ -8653,6 +8902,13 @@ CreateNewDecl:
InFunctionDeclarator && Name)
DeclsInPrototypeScope.push_back(New);
+ if (PrevDecl)
+ mergeDeclAttributes(New, PrevDecl);
+
+ // If there's a #pragma GCC visibility in scope, set the visibility of this
+ // record.
+ AddPushedVisibilityAttribute(New);
+
OwnedDecl = true;
return New;
}
@@ -8663,6 +8919,12 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
// Enter the tag context.
PushDeclContext(S, Tag);
+
+ ActOnDocumentableDecl(TagD);
+
+ // If there's a #pragma GCC visibility in scope, set the visibility of this
+ // record.
+ AddPushedVisibilityAttribute(Tag);
}
Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) {
@@ -8849,7 +9111,7 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart,
Declarator &D, Expr *BitfieldWidth) {
FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD),
DeclStart, D, static_cast<Expr*>(BitfieldWidth),
- /*HasInit=*/false, AS_public);
+ /*InitStyle=*/ICIS_NoInit, AS_public);
return Res;
}
@@ -8857,7 +9119,8 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart,
///
FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
SourceLocation DeclStart,
- Declarator &D, Expr *BitWidth, bool HasInit,
+ Declarator &D, Expr *BitWidth,
+ InClassInitStyle InitStyle,
AccessSpecifier AS) {
IdentifierInfo *II = D.getIdentifier();
SourceLocation Loc = DeclStart;
@@ -8919,7 +9182,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
= (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
SourceLocation TSSL = D.getLocStart();
FieldDecl *NewFD
- = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit,
+ = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, InitStyle,
TSSL, AS, PrevDecl, &D);
if (NewFD->isInvalidDecl())
@@ -8952,7 +9215,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
TypeSourceInfo *TInfo,
RecordDecl *Record, SourceLocation Loc,
- bool Mutable, Expr *BitWidth, bool HasInit,
+ bool Mutable, Expr *BitWidth,
+ InClassInitStyle InitStyle,
SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D) {
@@ -9042,7 +9306,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
- BitWidth, Mutable, HasInit);
+ BitWidth, Mutable, InitStyle);
if (InvalidDecl)
NewFD->setInvalidDecl();
@@ -9213,10 +9477,9 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
case CXXCopyAssignment:
if (RD->hasUserDeclaredCopyAssignment()) {
- // FIXME: this should use the location of the copy
- // assignment, not the type.
- SourceLocation TyLoc = RD->getLocStart();
- Diag(TyLoc, diag::note_nontrivial_user_defined) << QT << member;
+ SourceLocation AssignLoc =
+ RD->getCopyAssignmentOperator(0)->getLocation();
+ Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
return;
}
break;
@@ -9295,12 +9558,12 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
typedef RecordDecl::field_iterator field_iter;
for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe;
++fi) {
- QualType EltTy = Context.getBaseElementType((*fi)->getType());
+ QualType EltTy = Context.getBaseElementType(fi->getType());
if (const RecordType *EltRT = EltTy->getAs<RecordType>()) {
CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
if (!(EltRD->*hasTrivial)()) {
- SourceLocation FLoc = (*fi)->getLocation();
+ SourceLocation FLoc = fi->getLocation();
Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
DiagnoseNontrivial(EltRT, member);
return;
@@ -9316,7 +9579,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
case Qualifiers::OCL_Autoreleasing:
case Qualifiers::OCL_Weak:
case Qualifiers::OCL_Strong:
- Diag((*fi)->getLocation(), diag::note_nontrivial_objc_ownership)
+ Diag(fi->getLocation(), diag::note_nontrivial_objc_ownership)
<< QT << EltTy.getObjCLifetime();
return;
}
@@ -9390,7 +9653,7 @@ Decl *Sema::ActOnIvar(Scope *S,
ObjCContainerDecl *EnclosingContext;
if (ObjCImplementationDecl *IMPDecl =
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
- if (!LangOpts.ObjCNonFragileABI2) {
+ if (LangOpts.ObjCRuntime.isFragile()) {
// Case of ivar declared in an implementation. Context is that of its class.
EnclosingContext = IMPDecl->getClassInterface();
assert(EnclosingContext && "Implementation has no class interface!");
@@ -9400,7 +9663,7 @@ Decl *Sema::ActOnIvar(Scope *S,
} else {
if (ObjCCategoryDecl *CDecl =
dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
- if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) {
+ if (LangOpts.ObjCRuntime.isFragile() || !CDecl->IsClassExtension()) {
Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension();
return 0;
}
@@ -9443,7 +9706,11 @@ Decl *Sema::ActOnIvar(Scope *S,
S->AddDecl(NewID);
IdResolver.AddDecl(NewID);
}
-
+
+ if (LangOpts.ObjCRuntime.isNonFragile() &&
+ !NewID->isInvalidDecl() && isa<ObjCInterfaceDecl>(EnclosingDecl))
+ Diag(Loc, diag::warn_ivars_in_interface);
+
return NewID;
}
@@ -9453,7 +9720,7 @@ Decl *Sema::ActOnIvar(Scope *S,
/// then add an implicit `char :0` ivar to the end of that interface.
void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
SmallVectorImpl<Decl *> &AllIvarDecls) {
- if (!LangOpts.ObjCNonFragileABI2 || AllIvarDecls.empty())
+ if (LangOpts.ObjCRuntime.isFragile() || AllIvarDecls.empty())
return;
Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1];
@@ -9492,11 +9759,23 @@ void Sema::ActOnFields(Scope* S,
AttributeList *Attr) {
assert(EnclosingDecl && "missing record or interface decl");
- // If the decl this is being inserted into is invalid, then it may be a
- // redeclaration or some other bogus case. Don't try to add fields to it.
- if (EnclosingDecl->isInvalidDecl())
- return;
-
+ // If this is an Objective-C @implementation or category and we have
+ // new fields here we should reset the layout of the interface since
+ // it will now change.
+ if (!Fields.empty() && isa<ObjCContainerDecl>(EnclosingDecl)) {
+ ObjCContainerDecl *DC = cast<ObjCContainerDecl>(EnclosingDecl);
+ switch (DC->getKind()) {
+ default: break;
+ case Decl::ObjCCategory:
+ Context.ResetObjCLayout(cast<ObjCCategoryDecl>(DC)->getClassInterface());
+ break;
+ case Decl::ObjCImplementation:
+ Context.
+ ResetObjCLayout(cast<ObjCImplementationDecl>(DC)->getClassInterface());
+ break;
+ }
+ }
+
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
// Start counting up the number of named members; make sure to include
@@ -9704,7 +9983,7 @@ void Sema::ActOnFields(Scope* S,
// However, here we check whether this particular class is only
// non-POD because of the presence of an Objective-C pointer member.
// If so, objects of this type cannot be shared between code compiled
- // with instant objects and code compiled with manual retain/release.
+ // with ARC and code compiled with manual retain/release.
if (getLangOpts().ObjCAutoRefCount &&
CXXRecord->hasObjectMember() &&
CXXRecord->getLinkage() == ExternalLinkage) {
@@ -9848,11 +10127,6 @@ void Sema::ActOnFields(Scope* S,
if (Attr)
ProcessDeclAttributeList(S, Record, Attr);
-
- // If there's a #pragma GCC visibility in scope, and this isn't a subclass,
- // set the visibility of this record.
- if (Record && !Record->getDeclContext()->isRecord())
- AddPushedVisibilityAttribute(Record);
}
/// \brief Determine whether the given integral value is representable within
@@ -10106,15 +10380,16 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
}
}
- // C++ [class.mem]p13:
- // If T is the name of a class, then each of the following shall have a
- // name different from T:
- // - every enumerator of every member of class T that is an enumerated
- // type
+ // C++ [class.mem]p15:
+ // If T is the name of a class, then each of the following shall have a name
+ // different from T:
+ // - every enumerator of every member of class T that is an unscoped
+ // enumerated type
if (CXXRecordDecl *Record
= dyn_cast<CXXRecordDecl>(
TheEnumDecl->getDeclContext()->getRedeclContext()))
- if (Record->getIdentifier() && Record->getIdentifier() == Id)
+ if (!TheEnumDecl->isScoped() &&
+ Record->getIdentifier() && Record->getIdentifier() == Id)
Diag(IdLoc, diag::err_member_name_of_class) << Id;
EnumConstantDecl *New =
@@ -10129,9 +10404,62 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
PushOnScopeChains(New, S);
}
+ ActOnDocumentableDecl(New);
+
return New;
}
+// Emits a warning if every element in the enum is the same value and if
+// every element is initialized with a integer or boolean literal.
+static void CheckForUniqueEnumValues(Sema &S, Decl **Elements,
+ unsigned NumElements, EnumDecl *Enum,
+ QualType EnumType) {
+ if (S.Diags.getDiagnosticLevel(diag::warn_identical_enum_values,
+ Enum->getLocation()) ==
+ DiagnosticsEngine::Ignored)
+ return;
+
+ if (NumElements < 2)
+ return;
+
+ if (!Enum->getIdentifier())
+ return;
+
+ llvm::APSInt FirstVal;
+
+ for (unsigned i = 0; i != NumElements; ++i) {
+ EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]);
+ if (!ECD)
+ return;
+
+ Expr *InitExpr = ECD->getInitExpr();
+ if (!InitExpr)
+ return;
+ InitExpr = InitExpr->IgnoreImpCasts();
+ if (!isa<IntegerLiteral>(InitExpr) && !isa<CXXBoolLiteralExpr>(InitExpr))
+ return;
+
+ if (i == 0) {
+ FirstVal = ECD->getInitVal();
+ continue;
+ }
+
+ if (!llvm::APSInt::isSameValue(FirstVal, ECD->getInitVal()))
+ return;
+ }
+
+ S.Diag(Enum->getLocation(), diag::warn_identical_enum_values)
+ << EnumType << FirstVal.toString(10)
+ << Enum->getSourceRange();
+
+ EnumConstantDecl *Last = cast<EnumConstantDecl>(Elements[NumElements - 1]),
+ *Next = cast<EnumConstantDecl>(Elements[NumElements - 2]);
+
+ S.Diag(Last->getLocation(), diag::note_identical_enum_values)
+ << FixItHint::CreateReplacement(Last->getInitExpr()->getSourceRange(),
+ Next->getName());
+}
+
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, Decl *EnumDeclX,
Decl **Elements, unsigned NumElements,
@@ -10355,6 +10683,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
if (InFunctionDeclarator)
DeclsInPrototypeScope.push_back(Enum);
+ CheckForUniqueEnumValues(*this, Elements, NumElements, Enum, EnumType);
}
Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,