summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/Sema.h5
-rw-r--r--clang/lib/Sema/SemaDecl.cpp4
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp48
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp20
4 files changed, 72 insertions, 5 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 2d3f9fc8cb2..e0c3f135766 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -2149,6 +2149,11 @@ public:
bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old);
+ /// CheckOverridingFunctionAttributes - Checks whether attributes are
+ /// incompatible or prevent overriding.
+ bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old);
+
//===--------------------------------------------------------------------===//
// C++ Access Control
//
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 27c491c8820..f8ebe1624a8 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2613,7 +2613,8 @@ void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
E = Paths.found_decls_end(); I != E; ++I) {
if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
- !CheckOverridingFunctionExceptionSpec(MD, OldMD))
+ !CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
+ !CheckOverridingFunctionAttributes(MD, OldMD))
MD->addOverriddenMethod(OldMD);
}
}
@@ -2883,7 +2884,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
NewFD->setAccess(AS_public);
}
-
if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
AddOverriddenMethods(cast<CXXRecordDecl>(DC), NewMD);
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index c96ab4681cc..3fa7d9cddeb 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -464,7 +464,9 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
if (!isFunctionOrMethod(d) && !isa<BlockDecl>(d)) {
ValueDecl *VD = dyn_cast<ValueDecl>(d);
if (VD == 0 || !VD->getType()->isBlockPointerType()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ S.Diag(Attr.getLoc(),
+ Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
+ : diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return false;
}
@@ -484,6 +486,15 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
d->addAttr(::new (S.Context) AnalyzerNoReturnAttr());
}
+static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << 8; /*function, method, or parameter*/
+ return;
+ }
+ // FIXME: Actually store the attribute on the declaration
+}
+
static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
@@ -1516,6 +1527,10 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
+
+ //FIXME: The C++0x version of this attribute has more limited applicabilty
+ // than GNU's, and should error out when it is used to specify a
+ // weaker alignment, rather than being silently ignored.
unsigned Align = 0;
if (Attr.getNumArgs() == 0) {
@@ -1794,6 +1809,29 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) RegparmAttr(NumParams.getZExtValue()));
}
+static void HandleFinalAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<CXXRecordDecl>(d)
+ && (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(d)->isVirtual())) {
+ S.Diag(Attr.getLoc(),
+ Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
+ : diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 7 /*virtual method or class*/;
+ return;
+ }
+
+ // FIXME: Check that it's not specified more than once in an attribute-
+ // specifier and that it conforms to the C++0x rules for
+ // redeclarations.
+
+ d->addAttr(::new (S.Context) FinalAttr());
+}
+
//===----------------------------------------------------------------------===//
// Checker-specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -1841,7 +1879,8 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
/// the attribute applies to decls. If the attribute is a type attribute, just
-/// silently ignore it.
+/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to
+/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
static void ProcessDeclAttribute(Scope *scope, Decl *D,
const AttributeList &Attr, Sema &S) {
if (Attr.isDeclspecAttribute())
@@ -1861,6 +1900,8 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_analyzer_noreturn:
HandleAnalyzerNoReturnAttr (D, Attr, S); break;
case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
+ case AttributeList::AT_carries_dependency:
+ HandleDependencyAttr (D, Attr, S); break;
case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break;
case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break;
case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break;
@@ -1871,9 +1912,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
HandleExtVectorTypeAttr(scope, D, Attr, S);
break;
case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break;
+ case AttributeList::AT_final: HandleFinalAttr (D, Attr, S); break;
case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
- case AttributeList::AT_gnu_inline: HandleGNUInlineAttr(D, Attr, S); break;
+ case AttributeList::AT_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break;
case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break;
case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break;
case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index bda1a699393..45870a19e4c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -489,6 +489,13 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
Class->setEmpty(false);
if (CXXBaseDecl->isPolymorphic())
Class->setPolymorphic(true);
+ // C++0x CWG Issue #817 indicates that [[final]] classes shouldn't be bases.
+ if (CXXBaseDecl->hasAttr<FinalAttr>()) {
+ Diag(BaseLoc, diag::err_final_base) << BaseType.getAsString();
+ Diag(CXXBaseDecl->getLocation(), diag::note_previous_class_decl)
+ << BaseType.getAsString();
+ return 0;
+ }
// C++ [dcl.init.aggr]p1:
// An aggregate is [...] a class with [...] no base classes [...].
@@ -4896,6 +4903,19 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
return false;
}
+bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old)
+{
+ if (Old->hasAttr<FinalAttr>()) {
+ Diag(New->getLocation(), diag::err_final_function_overridden)
+ << New->getDeclName();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
+ }
+
+ return false;
+}
+
/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an
/// initializer for the declaration 'Dcl'.
/// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a
OpenPOWER on IntegriCloud